Running scHLA count
- NOTE: Filepaths for running scHLAcount on raw
sequencing data have not been refactored for github repo. All output
files relevant for downstream analysis have been moved to
data/isb/scHLAcount within the github repo.
Prepare reference genotype files
# Assemble key linking sample-pool to simplified sample
hla_samples <- read_tsv("../../covid/isb/scHLAcount/all_fastq_files.txt", col_names = "file") %>%
filter(grepl("^INCOV", file)) %>%
filter(grepl("-BL", file)) %>%
separate(file, into = c("sample", NA), sep = "_", remove = F) %>%
drop_na()
# From all genotype field results, assemble highest resolution genotype for all sample:genotypers
select_last_allele <- function(x){
x[!is.na(x)] %>%
tail(1) %>%
str_replace_all("_", ":")}
hla_key <- all_hla_expanded %>%
rowwise() %>%
filter(grepl("^[ABC]", locus)) %>%
mutate(allele = select_last_allele(across(contains("field")))) %>%
select(sample, genotyper, locus, allele) %>%
unite(allele, locus, allele, sep = "*")
# Merge into key of list of genotypes for each sample-pool:genotyper pair
hla_merge <- hla_samples %>%
left_join(hla_key, by = "sample") %>%
drop_na() %>%
select(-sample) %>%
group_by(file, genotyper) %>%
nest()
# # Write keys to set of csvs for input to scHLAcount
# hla_merge %>%
# mutate(write = pmap(list(data, file, genotyper), function(d,f,g){
# dir <- sprintf("../../covid/isb/scHLAcount/genotypes/%s",g)
# if (!dir.exists(dir)){dir.create(dir, recursive = T)}
# write_tsv(d,
# sprintf("%s/%s_hla.tsv",dir,f),
# col_names = F,
# )}))
Run script
sbatch /covid/scripts/isb_scHLAcount_benchmark.sh
#!/bin/sh
# SET GLOBAL VARIABLES
# General
export BASE_DIR=/labs/khatrilab/solomonb/covid/isb/scHLAcount
export LOG_DIR=$BASE_DIR/logs/$(date +'%y%m%d_%H%M%S')
# FASTQ/HISAT
export INDEX_DIR=/labs/khatrilab/solomonb/rnaseq_processing/hisat2/hisat_arcas/hisat_data/grch38
export BAM_DIR=$BASE_DIR/bam
# HLA references
export HLA_DIR=$BASE_DIR/hla_references
export HLANUC=/labs/khatrilab/solomonb/references/IMGTHLA/hla_nuc.fasta
export HLAGEN=/labs/khatrilab/solomonb/references/IMGTHLA/hla_gen.fasta
# SCHLA
export BARCODE_DIR=$BASE_DIR/barcodes
export GENOTYPE_DIR=$BASE_DIR/genotypes
export SCHLACOUNT_DIR=$BASE_DIR/output
export TEMP_DIR=$BASE_DIR/temp_fastq
# SLURM
export N_CORES=$SLURM_CPUS_PER_TASK
# CREATE DIRECTORIES
if [ ! -d $LOG_DIR ]; then mkdir -p $LOG_DIR;fi
if [ ! -d $BAM_DIR ]; then mkdir -p $BAM_DIR;fi
if [ ! -d $SCHLACOUNT_DIR ]; then mkdir -p $SCHLACOUNT_DIR;fi
if [ ! -d $TEMP_DIR ]; then mkdir -p $TEMP_DIR;fi
# CREATE HLA REFERECE ##########################################################
HLA_REFERENCE(){
source /labs/khatrilab/solomonb/miniconda3/etc/profile.d/conda.sh
conda activate samtools
printf "\n\
########################## CREATE REFERENCE ####################################\
\n" >> $LOG_DIR/${1}/${1}_${2}.log
printf "\n### [START___REFERENCE___$(date +'%D %X')]\n" >> $LOG_DIR/${1}/${1}_${2}.log
[ ! -d $HLA_DIR/${2} ] && mkdir -p $HLA_DIR/${2}
while read -r line; do grep -F -m 1 $line $HLANUC >> $HLA_DIR/${2}/${1}_tmpallele.txt; done < $GENOTYPE_DIR/${2}/${1}_hla.tsv
samtools faidx $HLANUC $(cut -f1 -d' ' $HLA_DIR/${2}/${1}_tmpallele.txt | tr '>' ' ' | tr '\n' ' ') > $HLA_DIR/${2}/${1}_cds.fasta 2>> $LOG_DIR/${1}/${1}_${2}.log
samtools faidx $HLAGEN $(cut -f1 -d' ' $HLA_DIR/${2}/${1}_tmpallele.txt | tr '>' ' ' | tr '\n' ' ') > $HLA_DIR/${2}/${1}_gen.fasta 2>> $LOG_DIR/${1}/${1}_${2}.log
while read -r line; do IFS=' '; read -r f1 f2 <<<"$line"; sed -i"" "s/$f1/$f1 $f2/g" $HLA_DIR/${2}/${1}_cds.fasta; done < $HLA_DIR/${2}/${1}_tmpallele.txt 2>> $LOG_DIR/${1}/${1}_${2}.log
while read -r line; do IFS=' '; read -r f1 f2 f3 <<<"$line"; sed -i"" "s/$f1/$f1 $f2/g" $HLA_DIR/${2}/${1}_gen.fasta; done < $HLA_DIR/${2}/${1}_tmpallele.txt 2>> $LOG_DIR/${1}/${1}_${2}.log
rm $HLA_DIR/${2}/${1}_tmpallele.txt
printf "### [COMPLETE___REFERENCE___$(date +'%D %X')]\n" >> $LOG_DIR/${1}/${1}_${2}.log
}
export -f HLA_REFERENCE
# DEFINE scHLA GENOTYPING PIPELINE #############################################
SCHLACOUNT(){
source /labs/khatrilab/solomonb/miniconda3/etc/profile.d/conda.sh
conda activate samtools
printf "\n\
########################## RUN SCHLACOUNT ####################################\
\n" >> $LOG_DIR/${1}/${1}_${2}.log
printf "\n### [START___SCHLACOUNT___$(date +'%D %X')]\n" >> $LOG_DIR/${1}/${1}_${2}.log
echo "### Starting scHLAcount at $(date +'%D %X')" >> $LOG_DIR/${1}/${1}_${2}.log
# if [ -d $SCHLACOUNT_DIR/${1}_results ]; then rm -r $SCHLACOUNT_DIR/${1}_results;fi
[ ! -d SCHLACOUNT_DIR/${2} ] && mkdir -p $SCHLACOUNT_DIR/${2}
sc_hla_count \
--bam $BAM_DIR/${1}.bam \
--cell-barcodes $BARCODE_DIR/${1}_barcode.tsv \
--out-dir $SCHLACOUNT_DIR/${2}/${1}_results \
--fasta-cds $HLA_DIR/${2}/${1}_cds.fasta \
--fasta-genomic $HLA_DIR/${2}/${1}_gen.fasta\
>> $LOG_DIR/${1}/${1}_${2}.log \
2>> $LOG_DIR/${1}/${1}_${2}.log
printf "### [COMPLETE___SCHLACOUNT___$(date +'%D %X')]\n" >> $LOG_DIR/${1}/${1}_${2}.log
}
export -f SCHLACOUNT
# DEFINE PIPELINE CONTROLLER FUNCTION ##########################################
PIPELINE(){
echo "START: sample $1 at $(date +'%D %X')"
for G in arcasHLA hlaminer invitro optitype phlat
do
[ ! -d $LOG_DIR/${1} ] && mkdir -p $LOG_DIR/${1}
HLA_REFERENCE $1 $G
SCHLACOUNT $1 $G
done
echo "COMPLETE: sample $1 at $(date +'%D %X')"
}
export -f PIPELINE
cat $BASE_DIR/BL_fastq_files.txt | parallel --delay 15 -j $SLURM_NTASKS --joblog $LOG_DIR/parallel.log PIPELINE {}
UMAP projections
Cell clusters
# srt <- readRDS("/labs/khatrilab/hongzheng/webapps/isb/srt_isb260.meta.rds")
srt <- readRDS(here("data/isb/isb_sc_metadata.RDS"))
cells <- c("CD14 Monocyte", "CD4 T", "CD8 T", "NK", "B", "CD16 Monocyte", "cDC", "pDC")
srt <- srt %>% select(sample, sampleID, cell, celltype, severity, UMAP_1, UMAP_2) %>%
filter(celltype %in% cells)
# ggplot theme to overlay cluster id #s on UMAP
gg_srt_relabel <- function(df, x_var, y_var, color_var, cell_fraction = 1){
plt <- df %>%
ggplot(aes(x = !!sym(x_var), y = !!sym(y_var), color = !!sym(color_var))) +
geom_point(size = 0.5, alpha = 0.5)+
theme_bw() +
scale_color_brewer(palette = "Dark2")+
guides(color = guide_legend(override.aes = list(size = 2, alpha = 1)))
g <- ggplot_build(plt)
plt_ids <- g$data[[1]]
group_levels <- levels(factor(g$plot$data[[g$plot$labels$colour]]))
plt_key <- g$data[[1]] %>%
select(colour, group) %>%
distinct() %>%
mutate(label = map_chr(group, function(x) group_levels[x])) %>%
mutate(label = factor(label, level = group_levels)) %>%
mutate(label = sprintf("%s) %s", 1:n(), label)) %>%
select(-group)
plt_df <- plt_ids %>%
left_join(plt_key, by = "colour")
plt_center <- plt_df %>%
group_by(label) %>% summarise(x = mean(x), y = mean(y)) %>%
mutate(label = gsub(").*","",label))
plt_repel <- plt_df %>%
ggplot(aes(x=x,y=y,color=label)) +
geom_point(size = 0.5)+
ggrepel::geom_text_repel(data=plt_center,
aes(label=label, bg.color="white", bg.r=0.25),
color = "black",
fontface = "bold") +
theme_bw() +
guides(color = guide_legend(override.aes = list(size = 2) ) ) +
labs(x=x_var, y = y_var, color = color_var) +
theme(axis.text = element_blank(), axis.ticks = element_blank())
return(plt_repel)
}
plt_srt <- srt %>%
filter(celltype %in% cells) %>%
filter(sampleID == "INCOV069-BL") %>%
gg_srt_relabel(x_var = "UMAP_1", y_var = "UMAP_2", color_var = "celltype", cell_fraction = 0.1) +
scale_color_brewer(palette = "Dark2")+
theme(axis.text = element_blank(), axis.ticks = element_blank()) +
labs(x="UMAP 1", y = "UMAP 2", color = "Cell Cluster")
plt_srt

Allele frequency
# samp <- "INCOV069-BL"
samp <- "INCOV028-BL"
gene_select <- "A"
scHLAcount_dir <- sprintf("%s/scHLAcount", isb_path)
# Create tibble of all genotyper and sample combinations
allele_data <- expand_grid(
genotyper = c("invitro", "arcasHLA", "optitype", "phlat", "hlaminer"),
sample = read_lines(
here("data/isb/scHLAcount/BL_fastq_files.txt")
)) %>%
filter(grepl(samp, sample)) %>%
# Import data based on sample and genotyper
mutate(result_path = sprintf("%s/scHLAcount/output_ase/%s",isb_path, genotyper),
barcode_path = sprintf("%s/scHLAcount/barcodes", isb_path)) %>%
mutate(data = pmap(list(sample, result_path, barcode_path), function(s,r,b){
df <- scHLA_data_processing(
sample=s,
result_dir=r,
barcode_dir=b
)
})) %>% unnest(data)
allele_data_ratios <- allele_data %>%
filter(gene == gene_select) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
mutate(allele_order = fct_recode(factor(allele_order), "Allele 1" = "1", "Allele 2" = "2"))
allele_label <- allele_data_ratios %>%
select(genotyper, allele_order, allele) %>%
distinct()
plt <- srt %>%
left_join(allele_data_ratios %>% filter(gene == gene_select), by = "cell") %>%
filter(!is.na(allele)) %>%
ggplot(aes(x = UMAP_1, y = UMAP_2, color = allele_ratio)) +
geom_point(size = 0.5, alpha = 0.5)+
theme_bw() +
facet_grid(allele_order~genotyper)+
scale_color_gradient2(high = "red", mid = "grey80", low = "blue", midpoint = 0.5, na.value = "transparent") +
labs(x="UMAP 1", y="UMAP 2", color = "Allele \nFrequency")+
theme(axis.ticks = element_blank(), axis.text = element_blank())+
coord_cartesian(ylim = c(-10,15))
plt_allele_freq <- plt+
geom_label(data = allele_label, aes(x=-10,y=14, color = NULL, label = allele), size = 3, hjust = 0)
plt_allele_freq

Maximum allele
# Create tibble of all genotyper and sample combinations
allele_max_ratio <- allele_data %>%
select(genotyper, cell, gene, allele_order, allele_ratio) %>%
# group_by(genotyper, cell, allele_order) %>% mutate(test = length(allele_order))
pivot_wider(names_from = "allele_order", values_from = "allele_ratio", names_prefix = "allele_") %>%
rowwise() %>%
mutate(max_ratio = max(across(contains("allele_")), na.rm = T)) %>%
select(genotyper, cell, gene, max_ratio) %>%
filter(gene == gene_select)
allele_label <- allele_data %>% select(sample, genotyper, gene, allele) %>%
filter(gene == gene_select) %>%
separate(sample, into = c("sample", NULL), sep = "_", extra = "drop") %>%
distinct() %>%
group_by(sample, genotyper, gene) %>% nest() %>% unnest_wider(data) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
mutate(allele = map_chr(allele, paste, collapse = "\n"))
plt_max_allele <- srt %>%
left_join(allele_max_ratio %>% filter(gene == gene_select), by = "cell") %>%
# mutate(genotyper = fct_relevel(genotyper, "invitro")) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
filter(!is.na(genotyper)) %>%
ggplot(aes(x = UMAP_1, y = UMAP_2, color = max_ratio)) +
geom_point(size = 0.5, alpha = 0.5)+
geom_label(data = allele_label, aes(color = NULL, label = allele, x = -Inf, y = -Inf),
hjust = -0.1, vjust = -0.1, size = 3, hjust = 0) +
theme_bw() +
facet_grid(.~genotyper)+
scale_color_gradient(high = "red", low = "blue", na.value = "transparent") +
labs(x="UMAP 1", y="UMAP 2", color = "Maximum Allele \nFrequency")+
theme(axis.ticks = element_blank(), axis.text = element_blank())
plt_max_allele

Meta-analysis approach
Rationale
- Goal: determine a summary statistic for allele ratio across all
cells
- Problem:
- Each cell in scRNA experiment has its own ratio of HLA allele 1
reads : HLA allele 2 reads
- A wide range of total read counts may go into each cell’s ratio
- Small difference in read counts for cells with low total reads can
greatly alter the allele ratio compared to cells with high total read
counts
- I.e. Cells with low read counts are more likely to have imprecise
allele ratios
- Simply averaging ratios would equally weight high confidence, high
read count ratios with low confidence, low read ratios
- Approach
- Meta-analysis methods specifically address type of problem,
typically by weighing an effect by the inverse of its variance
- In the setting of ratios, basic approach would be to combine
log-odds ratio of alleles, weighted by inverse variance
- Would use a random effects model because do not expect each cell in
a group would have the same exact ratio due to various stochastic
transcriptional effects
Calculating summary effect sizes
- Analysis can take some time, so run on an HPC cluster using
slurm
- Contained in a separate script
sc_meta.R:
Contents of sc_meta.R
library(tidyverse)
library(meta)
source(here("helper_functions/data_import_functions.R"))
isb_path <- here("data/isb")
srt <- readRDS(here("data/isb/isb_sc_metadata.RDS"))
cells <- c("CD14 Monocyte", "CD4 T", "CD8 T", "NK", "B", "CD16 Monocyte", "cDC", "pDC")
srt <- srt %>% select(sample, sampleID, cell, celltype, severity, UMAP_1, UMAP_2) %>%
filter(celltype %in% cells)
# Function to perform meta-analysis on dataframe where
# each row is a cell and columns:
# `observed` (reads of dominant allele)
# `gene_sum_typed` (total cell reads)
# `expected` (reads of one allele expected if 50:50 allele_1 : allele_2)
sc_meta <- function(df){
l <- nrow(df)
m <- metabin(event.e = observed, n.e = gene_sum_typed, event.c = expected, n.c = gene_sum_typed,
data = df,
method = "Inverse",
incr = 0.1,
sm = "OR")
data.frame(summary(m)$random) %>%
mutate(n_cells = l) %>%
select(TE, seTE, lower, upper, n_cells)
}
# Import data based on sample and genotyper
cell_stats <- expand_grid(
genotyper = c("invitro", "arcasHLA", "optitype", "phlat", "hlaminer"),
sample = read_lines(here("data/isb/scHLAcount/BL_fastq_files.txt"))) %>%
# head(5) %>% # Specify limit to number of meta-analyses
mutate(data = map2(sample, genotyper, function(s,g){
result_path = sprintf("%s/scHLAcount/output_ase/%s",isb_path, g)
barcode_path = sprintf("%s/scHLAcount/barcodes", isb_path)
scHLA_data_processing(sample = s,
result_dir = result_path,
barcode_dir = barcode_path)
})) %>% unnest(data) %>%
filter(!is.na(cell)) %>%
mutate(sample = gsub("_[A-Z][0-9]$","",sample)) %>% # Consolidate samples
left_join(srt %>% select(celltype, cell), by = "cell") %>% # Add celltypes
filter(celltype %in% cells) # Keep only standard cell types
meta_df <- cell_stats %>%
# Keep only most expressed allele (or random if 50:50)
group_by(sample, genotyper, gene, cell) %>%
slice_max(order_by = allele_ratio, n = 1, with_ties = F) %>%
ungroup() %>%
# Fill out contingency table
mutate(complement = gene_sum_typed - count,
expected = 0.5*gene_sum_typed) %>%
rename(observed = count) %>%
select(sample, genotyper, celltype, gene, observed, expected, gene_sum_typed) %>%
group_by(sample, genotyper, celltype, gene) %>%
# Nest and run meta-analysis
nest() %>%
ungroup() %>%
mutate(data = map(data,function(x) {sc_meta(x)})) %>%
unnest(data)
write_csv(meta_df, here("7_HLA_ASE/meta_analysis_results.csv"))
Single sample analysis
meta_df <- read_csv(here("7_HLA_ASE/meta_analysis_results.csv"))
Rows: 7299 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): sample, genotyper, celltype, gene
dbl (5): TE, seTE, lower, upper, n_cells
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
meta_df
# Single celltype and gene
plt_meta <- meta_df %>%
filter(sample == samp) %>%
filter(celltype == "NK", gene == "A") %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
ggplot(aes(x = genotyper, y = TE, ymin = lower, ymax = upper))+
geom_point()+
geom_errorbar()+
theme_bw()+
scale_y_continuous(limits = c(0,NA))+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL)
plt_meta

samp <- "INCOV069-BL"
samples <- unique(meta_df$sample)
for (i in 1:length(samples)){
plt_meta <- meta_df %>%
filter(sample == samples[i]) %>%
filter(celltype == "CD14 Monocyte", gene == "A") %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
ggplot(aes(x = genotyper, y = TE, ymin = lower, ymax = upper))+
geom_point()+
geom_errorbar()+
theme_bw()+
scale_y_continuous(limits = c(0,NA))+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL) +
ggtitle(samples[i])
print(plt_meta)
}
































































# All celltypes and genes
meta_df %>%
mutate(
celltype = factor(celltype, levels = c(
"cDC", "CD14 Monocyte", "B", "pDC", "CD16 Monocyte", "CD8 T", "CD4 T", "NK"))) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
mutate(gene = reformat_hla_loci(gene)) %>%
ggplot(aes(x = celltype, y = TE, ymin = lower, ymax = upper, fill = celltype))+
geom_bar(stat = "identity", position = "dodge", color = "black", size = 0.25)+
geom_errorbar(position = position_dodge(0.9), width =0.5)+
theme_bw()+
facet_grid(gene~genotyper, scales = "free_y")+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

meta_df %>%
mutate(
celltype = factor(celltype, levels = c(
"cDC", "CD14 Monocyte", "B", "pDC", "CD16 Monocyte", "CD8 T", "CD4 T", "NK"))) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
mutate(gene = reformat_hla_loci(gene)) %>%
ggplot(aes(x = genotyper, y = TE, ymin = lower, ymax = upper, fill = celltype))+
geom_bar(stat = "identity", position = "dodge", color = "black", size = 0.25)+
geom_errorbar(position = position_dodge(0.9), width =0.5)+
theme_bw()+
facet_grid(gene~celltype, scales = "free_y")+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

Multi-sample analysis
meta_df <- read_csv(here("7_HLA_ASE/meta_analysis_results.csv")) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper),
celltype = factor(celltype, levels = c(
"cDC", "CD14 Monocyte", "B", "pDC", "CD16 Monocyte", "CD8 T", "CD4 T", "NK")))
Rows: 7299 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): sample, genotyper, celltype, gene
dbl (5): TE, seTE, lower, upper, n_cells
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
meta_df %>%
ggplot(aes(x=celltype,y=TE, fill = celltype))+
geom_violin()+
geom_jitter(alpha = 0.2, size = 0.2)+
stat_summary(fun=mean, stat= "point")+
stat_summary(fun.data = mean_se, geom="errorbar")+
facet_grid(gene~genotyper)+
theme_bw()+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

meta_df %>%
ggplot(aes(x=genotyper,y=TE, fill = celltype))+
geom_violin()+
geom_jitter(alpha = 0.2, size = 0.2)+
stat_summary(fun=mean, stat= "point")+
stat_summary(fun.data = mean_se, geom="errorbar")+
facet_grid(gene~celltype)+
theme_bw()+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

Correlation analysis
meta_df %>%
filter(gene == "A", celltype == "cDC") %>%
select(sample, genotyper, TE) %>%
pivot_wider(names_from = "genotyper", values_from = "TE") %>%
select(-sample) %>%
GGally::ggpairs(progress = FALSE) +
theme_bw()

accuracy_df <- readRDS(here("3_DRB/isb_accuracy_drb345_filtered.RDS")) %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
select(sample, gene=locus, genotyper, accuracy) %>%
distinct()
for (i in c(0,1)){
suppressWarnings({
plt <- meta_df %>%
ungroup() %>%
filter(gene == "A", celltype == "cDC") %>%
left_join(accuracy_df, by = c("sample", "gene", "genotyper")) %>%
filter(accuracy == i | genotyper == "Ground truth") %>%
# drop_na(accuracy) %>%
select(sample, genotyper, TE) %>%
pivot_wider(names_from = "genotyper", values_from = "TE") %>%
select(-sample) %>%
GGally::ggpairs(progress = FALSE) +
theme_bw() +
ggtitle(sprintf("Correlation of allele ratios where accuracy = %s", i))
print(plt)
})
}


corr_df <- meta_df %>%
mutate(genotyper = reformat_hla_genotyper(genotyper)) %>%
select(sample, genotyper, celltype, gene, TE) %>%
pivot_wider(names_from = "genotyper", values_from = "TE") %>%
pivot_longer(c(arcasHLA, HLAminer, OptiType, PHLAT), names_to = "genotyper", values_to = "TE") %>%
mutate(genotyper = reformat_hla_genotyper(genotyper))
corr_df %>%
ggplot(aes(x=`Ground truth`, y=TE))+
geom_point(size = 0.5)+
facet_grid(gene ~ genotyper) +
theme_bw() +
ggpubr::stat_cor(aes(label = ..rr.label..), label.x.npc = "left", label.y.npc = "top", geom = "label")

for (i in c(0,1)){
suppressWarnings({
plt <- corr_df %>%
ungroup() %>%
# filter(gene == "A", celltype == "cDC") %>%
left_join(accuracy_df, by = c("sample", "gene", "genotyper")) %>%
filter(accuracy == i) %>%
ggplot(aes(x=`Ground truth`, y=TE))+
geom_point(size = 0.5)+
facet_grid(gene ~ genotyper) +
theme_bw() +
ggpubr::stat_cor(aes(label = ..rr.label..), label.x.npc = "left", label.y.npc = "top", geom = "label") +
ggtitle(sprintf("Correlation of allele ratios where accuracy = %s", i)) +
labs(y = "Predicted genotype HLA allele log-odds ratio", x = "Ground truth genotype HLA allele log-odds ratio")
assign(sprintf("plt_meta_corr_%s", i), plt)
print(plt)
})
}


plt_meta_corr_abbrev <- corr_df %>%
left_join(accuracy_df, by = c("sample", "gene", "genotyper")) %>%
filter(gene == "A", accuracy %in% c(0,0.5,1)) %>%
ggplot(aes(x=`Ground truth`, y=TE))+
geom_point(size = 0.5)+
facet_grid(accuracy ~ genotyper, labeller = labeller(accuracy = function(x) sprintf("Accuracy: %s", x))) +
theme_bw() +
ggpubr::stat_cor(aes(label = ..rr.label..), label.x.npc = "left", label.y.npc = "top", geom = "label", method = "pearson") +
labs(y = "Log-odds ratio using predicted genotype", x = "Log-odds ratio using ground truth genotyper")
plt_meta_corr_abbrev
Warning: Removed 178 rows containing non-finite values (stat_cor).
Warning: Removed 178 rows containing missing values (geom_point).

accuracy_df %>%
ungroup() %>%
drop_na() %>%
count(gene, genotyper, accuracy)
By severity
meta_df %>%
filter(genotyper == "Ground truth") %>%
left_join(
srt %>%
select(sample = sampleID, severity) %>%
distinct(),
by = "sample"
) %>%
ggplot(aes(x=severity,y=TE, fill = celltype))+
geom_violin()+
geom_jitter(alpha = 0.2, size = 0.2)+
stat_summary(fun=mean, stat= "point")+
stat_summary(fun.data = mean_se, geom="errorbar")+
facet_grid(gene~celltype)+
theme_bw()+
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "Log-Odds ratio of dominant allele", x= NULL, fill = "Cell type") +
scale_fill_brewer(palette = "Dark2")

meta_df %>%
filter(genotyper == "Ground truth") %>%
left_join(
srt %>%
select(sample = sampleID, severity) %>%
distinct(),
by = "sample"
) %>%
mutate(severity = as.numeric(severity)) %>%
ggplot(aes(x = severity, y = TE)) +
geom_point() +
stat_smooth(method = "lm")+
facet_wrap(~celltype)+
theme_bw()
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 24 rows containing non-finite values (stat_smooth).
Warning: Removed 24 rows containing missing values (geom_point).

Assemble plot
# plt_allele_freq_lgd <- cowplot::get_legend(plt_allele_freq)
# plt_max_allele_lgd <- cowplot::get_legend(plt_max_allele)
col_1 <- plot_grid(
plt_allele_freq,
plt_max_allele,
ncol = 1,
rel_heights = c(5,3),
align = "v", axis = "lr",
labels = LETTERS[1:2]
)
col_2 <- plot_grid(
plt_srt,
plt_meta,
ncol = 1,
align = "v", axis = "lr",
labels = LETTERS[3:4],
hjust = 0.5
)
row_1 <- plot_grid(
col_1,
col_2,
nrow = 1,
rel_widths = c(6,3)
)
row_2 <- plot_grid(
plt_meta_corr_0 +ggtitle(NULL),
plt_meta_corr_1 +ggtitle(NULL),
labels = LETTERS[5:6],
ncol = 2
)
Warning: Removed 334 rows containing non-finite values (stat_cor).
Warning: Removed 334 rows containing missing values (geom_point).
Warning: Removed 14 rows containing non-finite values (stat_cor).
Warning: Removed 14 rows containing missing values (geom_point).
plot_grid(
row_1,
row_2,
rel_heights = c(3,2),
ncol = 1
)

col_1 <- plot_grid(
plt_srt,
plt_meta,
ncol = 1,
align = "v", axis = "lr",
labels = LETTERS[c(1,3)],
label_x = -0.05
)
col_2 <- plot_grid(
plt_max_allele,
plt_meta_corr_abbrev,
ncol = 1,
rel_heights = c(3,5),
align = "v", axis = "lr",
labels = LETTERS[c(2,4)],
label_x = -0.05
)
Warning: Removed 178 rows containing non-finite values (stat_cor).
Warning: Removed 178 rows containing missing values (geom_point).
plt_fig_main <- plot_grid(
NULL,
col_1,
col_2,
nrow = 1,
rel_widths = c(0.25,3,6)
)
plt_fig_main

col_1 <- plot_grid(
plt_srt,
plt_meta+ labs(y="Log-odds ratio\nof dominant allele"),
ncol = 1,
align = "v", axis = "lr",
labels = LETTERS[c(1,3)],
label_x = -0.05
)
col_2 <- plot_grid(
plt_max_allele,
plt_meta_corr_abbrev + facet_grid(. ~ genotyper) + labs(y="Log-odds ratio using\npredicted genotype"),
ncol = 1,
rel_heights = c(1,1),
align = "v", axis = "lr",
labels = LETTERS[c(2,4)],
label_x = -0.05
)
Warning: Removed 178 rows containing non-finite values (stat_cor).
Warning: Removed 178 rows containing missing values (geom_point).
plt_fig_main <- plot_grid(
NULL,
col_1,
NULL,
col_2,
nrow = 1,
rel_widths = c(0.25,3,0.25,6)
)
plt_fig_main

save_plot(here("figures_pdf/v2/7_scHLA.pdf"), plt_fig_main, base_height = 5, base_width = 14)
plt_fig_supp <- plt_meta_corr_abbrev + facet_grid(accuracy ~ genotyper, margins = "accuracy")
plt_fig_supp
Warning: Removed 356 rows containing non-finite values (stat_cor).
Warning: Removed 356 rows containing missing values (geom_point).

save_plot(here("figures_pdf/v2/s6_scHLA.pdf"), plt_fig_supp, base_height = 5, base_width = 6)
LS0tCnRpdGxlOiAiNykgRWZmZWN0IG9mIGdlbm90eXBlcnMgb24gSExBIGFsbGVsZS1zcGVjaWZpYyBleHByZXNzaW9uIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgojIFNldHVwCmBgYHtyLCBtZXNzYWdlID0gRn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobWV0YSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGhlcmUpCgpzb3VyY2UoaGVyZSgiaGVscGVyX2Z1bmN0aW9ucy9kYXRhX2ltcG9ydF9mdW5jdGlvbnMuUiIpKQpzb3VyY2UoaGVyZSgiaGVscGVyX2Z1bmN0aW9ucy9maWd1cmVfZm9ybWF0X2Z1bmN0aW9ucy5SIikpCnNvdXJjZShoZXJlKCJoZWxwZXJfZnVuY3Rpb25zL2NhbGN1bGF0aW9uX2Z1bmN0aW9ucy5SIikpCmFsbF9obGFfZXhwYW5kZWQgPC0gcmVhZFJEUyhoZXJlKCIyX2FjY3VyYWN5L2FsbF9obGFfZXhwYW5kZWQuUkRTIikpCmlzYl9wYXRoIDwtIGhlcmUoImRhdGEvaXNiIikKYGBgCgoKIyBSdW5uaW5nIHNjSExBIGNvdW50CgotICoqTk9URToqKiBGaWxlcGF0aHMgZm9yIHJ1bm5pbmcgc2NITEFjb3VudCBvbiByYXcgc2VxdWVuY2luZyBkYXRhIGhhdmUgbm90IGJlZW4gcmVmYWN0b3JlZCBmb3IgZ2l0aHViIHJlcG8uIEFsbCBvdXRwdXQgZmlsZXMgcmVsZXZhbnQgZm9yIGRvd25zdHJlYW0gYW5hbHlzaXMgaGF2ZSBiZWVuIG1vdmVkIHRvIGBkYXRhL2lzYi9zY0hMQWNvdW50YCB3aXRoaW4gdGhlIGdpdGh1YiByZXBvLiAgCgojIyMgUHJlcGFyZSByZWZlcmVuY2UgZ2Vub3R5cGUgZmlsZXMKCmBgYHtyLCBldmFsPUZ9CiMgQXNzZW1ibGUga2V5IGxpbmtpbmcgc2FtcGxlLXBvb2wgdG8gc2ltcGxpZmllZCBzYW1wbGUKaGxhX3NhbXBsZXMgPC0gcmVhZF90c3YoIi4uLy4uL2NvdmlkL2lzYi9zY0hMQWNvdW50L2FsbF9mYXN0cV9maWxlcy50eHQiLCBjb2xfbmFtZXMgPSAiZmlsZSIpICU+JSAKICBmaWx0ZXIoZ3JlcGwoIl5JTkNPViIsIGZpbGUpKSAlPiUgCiAgZmlsdGVyKGdyZXBsKCItQkwiLCBmaWxlKSkgJT4lIAogIHNlcGFyYXRlKGZpbGUsIGludG8gPSBjKCJzYW1wbGUiLCBOQSksIHNlcCA9ICJfIiwgcmVtb3ZlID0gRikgJT4lIAogIGRyb3BfbmEoKQoKIyBGcm9tIGFsbCBnZW5vdHlwZSBmaWVsZCByZXN1bHRzLCBhc3NlbWJsZSBoaWdoZXN0IHJlc29sdXRpb24gZ2Vub3R5cGUgZm9yIGFsbCBzYW1wbGU6Z2Vub3R5cGVycwpzZWxlY3RfbGFzdF9hbGxlbGUgPC0gZnVuY3Rpb24oeCl7CiAgeFshaXMubmEoeCldICU+JQogICAgdGFpbCgxKSAlPiUgCiAgICBzdHJfcmVwbGFjZV9hbGwoIl8iLCAiOiIpfQpobGFfa2V5IDwtIGFsbF9obGFfZXhwYW5kZWQgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgZmlsdGVyKGdyZXBsKCJeW0FCQ10iLCBsb2N1cykpICU+JSAKICBtdXRhdGUoYWxsZWxlID0gc2VsZWN0X2xhc3RfYWxsZWxlKGFjcm9zcyhjb250YWlucygiZmllbGQiKSkpKSAlPiUgCiAgc2VsZWN0KHNhbXBsZSwgZ2Vub3R5cGVyLCBsb2N1cywgYWxsZWxlKSAlPiUgCiAgdW5pdGUoYWxsZWxlLCBsb2N1cywgYWxsZWxlLCBzZXAgPSAiKiIpCgojIE1lcmdlIGludG8ga2V5IG9mIGxpc3Qgb2YgZ2Vub3R5cGVzIGZvciBlYWNoIHNhbXBsZS1wb29sOmdlbm90eXBlciBwYWlyCmhsYV9tZXJnZSA8LSBobGFfc2FtcGxlcyAlPiUgCiAgbGVmdF9qb2luKGhsYV9rZXksIGJ5ID0gInNhbXBsZSIpICU+JSAKICBkcm9wX25hKCkgJT4lIAogIHNlbGVjdCgtc2FtcGxlKSAlPiUgCiAgZ3JvdXBfYnkoZmlsZSwgZ2Vub3R5cGVyKSAlPiUgCiAgbmVzdCgpCgojICMgV3JpdGUga2V5cyB0byBzZXQgb2YgY3N2cyBmb3IgaW5wdXQgdG8gc2NITEFjb3VudAojIGhsYV9tZXJnZSAlPiUgCiMgICBtdXRhdGUod3JpdGUgPSBwbWFwKGxpc3QoZGF0YSwgZmlsZSwgZ2Vub3R5cGVyKSwgZnVuY3Rpb24oZCxmLGcpewojICAgICBkaXIgPC0gc3ByaW50ZigiLi4vLi4vY292aWQvaXNiL3NjSExBY291bnQvZ2Vub3R5cGVzLyVzIixnKQojICAgICBpZiAoIWRpci5leGlzdHMoZGlyKSl7ZGlyLmNyZWF0ZShkaXIsIHJlY3Vyc2l2ZSA9IFQpfQojICAgICB3cml0ZV90c3YoZCwgCiMgICAgICAgICAgICAgICBzcHJpbnRmKCIlcy8lc19obGEudHN2IixkaXIsZiksIAojICAgICAgICAgICAgICAgY29sX25hbWVzID0gRiwKIyAgICAgICAgICAgICAgICl9KSkKYGBgCgoKIyMjIFJ1biBzY3JpcHQKCmBzYmF0Y2ggL2NvdmlkL3NjcmlwdHMvaXNiX3NjSExBY291bnRfYmVuY2htYXJrLnNoYAoKYGBge2Jhc2gsIGV2YWw9Rn0KIyEvYmluL3NoCgojIFNFVCBHTE9CQUwgVkFSSUFCTEVTCiMgR2VuZXJhbApleHBvcnQgQkFTRV9ESVI9L2xhYnMva2hhdHJpbGFiL3NvbG9tb25iL2NvdmlkL2lzYi9zY0hMQWNvdW50CmV4cG9ydCBMT0dfRElSPSRCQVNFX0RJUi9sb2dzLyQoZGF0ZSArJyV5JW0lZF8lSCVNJVMnKQojIEZBU1RRL0hJU0FUCmV4cG9ydCBJTkRFWF9ESVI9L2xhYnMva2hhdHJpbGFiL3NvbG9tb25iL3JuYXNlcV9wcm9jZXNzaW5nL2hpc2F0Mi9oaXNhdF9hcmNhcy9oaXNhdF9kYXRhL2dyY2gzOApleHBvcnQgQkFNX0RJUj0kQkFTRV9ESVIvYmFtCiMgSExBIHJlZmVyZW5jZXMKZXhwb3J0IEhMQV9ESVI9JEJBU0VfRElSL2hsYV9yZWZlcmVuY2VzCmV4cG9ydCBITEFOVUM9L2xhYnMva2hhdHJpbGFiL3NvbG9tb25iL3JlZmVyZW5jZXMvSU1HVEhMQS9obGFfbnVjLmZhc3RhCmV4cG9ydCBITEFHRU49L2xhYnMva2hhdHJpbGFiL3NvbG9tb25iL3JlZmVyZW5jZXMvSU1HVEhMQS9obGFfZ2VuLmZhc3RhCiMgU0NITEEKZXhwb3J0IEJBUkNPREVfRElSPSRCQVNFX0RJUi9iYXJjb2RlcwpleHBvcnQgR0VOT1RZUEVfRElSPSRCQVNFX0RJUi9nZW5vdHlwZXMKZXhwb3J0IFNDSExBQ09VTlRfRElSPSRCQVNFX0RJUi9vdXRwdXQKZXhwb3J0IFRFTVBfRElSPSRCQVNFX0RJUi90ZW1wX2Zhc3RxCiMgU0xVUk0gCmV4cG9ydCBOX0NPUkVTPSRTTFVSTV9DUFVTX1BFUl9UQVNLCgoKIyBDUkVBVEUgRElSRUNUT1JJRVMKaWYgWyAhIC1kICRMT0dfRElSIF07IHRoZW4gbWtkaXIgLXAgJExPR19ESVI7ZmkKaWYgWyAhIC1kICRCQU1fRElSIF07IHRoZW4gbWtkaXIgLXAgJEJBTV9ESVI7ZmkKaWYgWyAhIC1kICRTQ0hMQUNPVU5UX0RJUiBdOyB0aGVuIG1rZGlyIC1wICRTQ0hMQUNPVU5UX0RJUjtmaQppZiBbICEgLWQgJFRFTVBfRElSIF07IHRoZW4gbWtkaXIgLXAgJFRFTVBfRElSO2ZpCgojIENSRUFURSBITEEgUkVGRVJFQ0UgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpITEFfUkVGRVJFTkNFKCl7CiAgc291cmNlIC9sYWJzL2toYXRyaWxhYi9zb2xvbW9uYi9taW5pY29uZGEzL2V0Yy9wcm9maWxlLmQvY29uZGEuc2gKICBjb25kYSBhY3RpdmF0ZSBzYW10b29scwogIAogIHByaW50ZiAiXG5cCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIENSRUFURSBSRUZFUkVOQ0UgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjXAogIFxuIiA+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICBwcmludGYgIlxuIyMjIFtTVEFSVF9fX1JFRkVSRU5DRV9fXyQoZGF0ZSArJyVEICVYJyldXG4iID4+ICRMT0dfRElSLyR7MX0vJHsxfV8kezJ9LmxvZwogIAogIFsgISAtZCAkSExBX0RJUi8kezJ9IF0gJiYgbWtkaXIgLXAgJEhMQV9ESVIvJHsyfQogIAogIHdoaWxlIHJlYWQgLXIgbGluZTsgZG8gZ3JlcCAtRiAtbSAxICRsaW5lICRITEFOVUMgPj4gJEhMQV9ESVIvJHsyfS8kezF9X3RtcGFsbGVsZS50eHQ7IGRvbmUgPCAkR0VOT1RZUEVfRElSLyR7Mn0vJHsxfV9obGEudHN2CiAgCiAgc2FtdG9vbHMgZmFpZHggICRITEFOVUMgJChjdXQgLWYxIC1kJyAnICRITEFfRElSLyR7Mn0vJHsxfV90bXBhbGxlbGUudHh0IHwgdHIgJz4nICcgJyB8IHRyICdcbicgJyAnKSA+ICRITEFfRElSLyR7Mn0vJHsxfV9jZHMuZmFzdGEgMj4+ICRMT0dfRElSLyR7MX0vJHsxfV8kezJ9LmxvZwogIHNhbXRvb2xzIGZhaWR4ICAkSExBR0VOICQoY3V0IC1mMSAtZCcgJyAkSExBX0RJUi8kezJ9LyR7MX1fdG1wYWxsZWxlLnR4dCB8IHRyICc+JyAnICcgfCB0ciAnXG4nICcgJykgPiAkSExBX0RJUi8kezJ9LyR7MX1fZ2VuLmZhc3RhIDI+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICAKICB3aGlsZSByZWFkIC1yIGxpbmU7IGRvIElGUz0nICc7IHJlYWQgLXIgZjEgZjIgPDw8IiRsaW5lIjsgc2VkIC1pIiIgInMvJGYxLyRmMSAkZjIvZyIgJEhMQV9ESVIvJHsyfS8kezF9X2Nkcy5mYXN0YTsgZG9uZSA8ICRITEFfRElSLyR7Mn0vJHsxfV90bXBhbGxlbGUudHh0IDI+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICB3aGlsZSByZWFkIC1yIGxpbmU7IGRvIElGUz0nICc7IHJlYWQgLXIgZjEgZjIgZjMgPDw8IiRsaW5lIjsgc2VkIC1pIiIgInMvJGYxLyRmMSAkZjIvZyIgJEhMQV9ESVIvJHsyfS8kezF9X2dlbi5mYXN0YTsgZG9uZSA8ICRITEFfRElSLyR7Mn0vJHsxfV90bXBhbGxlbGUudHh0IDI+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICAKICBybSAkSExBX0RJUi8kezJ9LyR7MX1fdG1wYWxsZWxlLnR4dAogIHByaW50ZiAiIyMjIFtDT01QTEVURV9fX1JFRkVSRU5DRV9fXyQoZGF0ZSArJyVEICVYJyldXG4iID4+ICRMT0dfRElSLyR7MX0vJHsxfV8kezJ9LmxvZwp9CmV4cG9ydCAtZiBITEFfUkVGRVJFTkNFCgoKIyBERUZJTkUgc2NITEEgR0VOT1RZUElORyBQSVBFTElORSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKU0NITEFDT1VOVCgpewogIHNvdXJjZSAvbGFicy9raGF0cmlsYWIvc29sb21vbmIvbWluaWNvbmRhMy9ldGMvcHJvZmlsZS5kL2NvbmRhLnNoCiAgY29uZGEgYWN0aXZhdGUgc2FtdG9vbHMKICAKICBwcmludGYgIlxuXAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBSVU4gU0NITEFDT1VOVCAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyNcCiAgXG4iID4+ICRMT0dfRElSLyR7MX0vJHsxfV8kezJ9LmxvZwogIHByaW50ZiAiXG4jIyMgW1NUQVJUX19fU0NITEFDT1VOVF9fXyQoZGF0ZSArJyVEICVYJyldXG4iID4+ICRMT0dfRElSLyR7MX0vJHsxfV8kezJ9LmxvZwogIAogIGVjaG8gIiMjIyBTdGFydGluZyAgc2NITEFjb3VudCBhdCAkKGRhdGUgKyclRCAlWCcpIiA+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKICAKICAjIGlmIFsgLWQgJFNDSExBQ09VTlRfRElSLyR7MX1fcmVzdWx0cyBdOyB0aGVuIHJtIC1yICRTQ0hMQUNPVU5UX0RJUi8kezF9X3Jlc3VsdHM7ZmkKICBbICEgLWQgU0NITEFDT1VOVF9ESVIvJHsyfSBdICYmIG1rZGlyIC1wICRTQ0hMQUNPVU5UX0RJUi8kezJ9CgogIHNjX2hsYV9jb3VudCBcCiAgLS1iYW0gJEJBTV9ESVIvJHsxfS5iYW0gXAogIC0tY2VsbC1iYXJjb2RlcyAkQkFSQ09ERV9ESVIvJHsxfV9iYXJjb2RlLnRzdiBcCiAgLS1vdXQtZGlyICRTQ0hMQUNPVU5UX0RJUi8kezJ9LyR7MX1fcmVzdWx0cyBcCiAgLS1mYXN0YS1jZHMgJEhMQV9ESVIvJHsyfS8kezF9X2Nkcy5mYXN0YSBcCiAgLS1mYXN0YS1nZW5vbWljICRITEFfRElSLyR7Mn0vJHsxfV9nZW4uZmFzdGFcCiAgPj4gJExPR19ESVIvJHsxfS8kezF9XyR7Mn0ubG9nIFwKICAyPj4gJExPR19ESVIvJHsxfS8kezF9XyR7Mn0ubG9nCgogIHByaW50ZiAiIyMjIFtDT01QTEVURV9fX1NDSExBQ09VTlRfX18kKGRhdGUgKyclRCAlWCcpXVxuIiA+PiAkTE9HX0RJUi8kezF9LyR7MX1fJHsyfS5sb2cKfQpleHBvcnQgLWYgU0NITEFDT1VOVAoKCiMgREVGSU5FIFBJUEVMSU5FIENPTlRST0xMRVIgRlVOQ1RJT04gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjClBJUEVMSU5FKCl7CiAgZWNobyAiU1RBUlQ6IHNhbXBsZSAkMSBhdCAkKGRhdGUgKyclRCAlWCcpIgogIGZvciBHIGluIGFyY2FzSExBIGhsYW1pbmVyIGludml0cm8gb3B0aXR5cGUgcGhsYXQKICBkbwogICAgWyAhIC1kICRMT0dfRElSLyR7MX0gXSAmJiBta2RpciAtcCAkTE9HX0RJUi8kezF9CiAgICBITEFfUkVGRVJFTkNFICQxICRHCiAgICBTQ0hMQUNPVU5UICQxICRHCiAgZG9uZQogIGVjaG8gIkNPTVBMRVRFOiBzYW1wbGUgJDEgYXQgJChkYXRlICsnJUQgJVgnKSIKfQpleHBvcnQgLWYgUElQRUxJTkUKCmNhdCAkQkFTRV9ESVIvQkxfZmFzdHFfZmlsZXMudHh0IHwgcGFyYWxsZWwgLS1kZWxheSAxNSAtaiAkU0xVUk1fTlRBU0tTIC0tam9ibG9nICRMT0dfRElSL3BhcmFsbGVsLmxvZyBQSVBFTElORSB7fQpgYGAKCgojIFVNQVAgcHJvamVjdGlvbnMKCiMjIyBDZWxsIGNsdXN0ZXJzCgpgYGB7cn0KIyBzcnQgPC0gcmVhZFJEUygiL2xhYnMva2hhdHJpbGFiL2hvbmd6aGVuZy93ZWJhcHBzL2lzYi9zcnRfaXNiMjYwLm1ldGEucmRzIikKc3J0IDwtIHJlYWRSRFMoaGVyZSgiZGF0YS9pc2IvaXNiX3NjX21ldGFkYXRhLlJEUyIpKQpjZWxscyA8LSBjKCJDRDE0IE1vbm9jeXRlIiwgIkNENCBUIiwgIkNEOCBUIiwgIk5LIiwgIkIiLCAiQ0QxNiBNb25vY3l0ZSIsICJjREMiLCAicERDIikKc3J0IDwtIHNydCAlPiUgc2VsZWN0KHNhbXBsZSwgc2FtcGxlSUQsIGNlbGwsIGNlbGx0eXBlLCBzZXZlcml0eSwgVU1BUF8xLCBVTUFQXzIpICU+JSAKICBmaWx0ZXIoY2VsbHR5cGUgJWluJSBjZWxscykKYGBgCgpgYGB7cn0KIyBnZ3Bsb3QgdGhlbWUgdG8gb3ZlcmxheSBjbHVzdGVyIGlkICNzIG9uIFVNQVAKZ2dfc3J0X3JlbGFiZWwgPC0gZnVuY3Rpb24oZGYsIHhfdmFyLCB5X3ZhciwgY29sb3JfdmFyLCBjZWxsX2ZyYWN0aW9uID0gMSl7CiAgcGx0IDwtIGRmICU+JSAKICAgIGdncGxvdChhZXMoeCA9ICEhc3ltKHhfdmFyKSwgeSA9ICEhc3ltKHlfdmFyKSwgY29sb3IgPSAhIXN5bShjb2xvcl92YXIpKSkgKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41LCBhbHBoYSA9IDAuNSkrCiAgICB0aGVtZV9idygpICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikrCiAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMiwgYWxwaGEgPSAxKSkpCiAgCiAgZyA8LSBnZ3Bsb3RfYnVpbGQocGx0KQogIAogIHBsdF9pZHMgPC0gZyRkYXRhW1sxXV0KICBncm91cF9sZXZlbHMgPC0gbGV2ZWxzKGZhY3RvcihnJHBsb3QkZGF0YVtbZyRwbG90JGxhYmVscyRjb2xvdXJdXSkpCiAgCiAgcGx0X2tleSA8LSBnJGRhdGFbWzFdXSAlPiUgCiAgICBzZWxlY3QoY29sb3VyLCBncm91cCkgJT4lIAogICAgZGlzdGluY3QoKSAlPiUgCiAgICBtdXRhdGUobGFiZWwgPSBtYXBfY2hyKGdyb3VwLCBmdW5jdGlvbih4KSBncm91cF9sZXZlbHNbeF0pKSAlPiUgCiAgICBtdXRhdGUobGFiZWwgPSBmYWN0b3IobGFiZWwsIGxldmVsID0gZ3JvdXBfbGV2ZWxzKSkgJT4lCiAgICBtdXRhdGUobGFiZWwgPSBzcHJpbnRmKCIlcykgJXMiLCAxOm4oKSwgbGFiZWwpKSAlPiUgCiAgICBzZWxlY3QoLWdyb3VwKQogIAogIHBsdF9kZiA8LSBwbHRfaWRzICU+JSAKICAgIGxlZnRfam9pbihwbHRfa2V5LCBieSA9ICJjb2xvdXIiKQogIAogIHBsdF9jZW50ZXIgPC0gcGx0X2RmICU+JSAKICAgIGdyb3VwX2J5KGxhYmVsKSAlPiUgc3VtbWFyaXNlKHggPSBtZWFuKHgpLCB5ID0gbWVhbih5KSkgJT4lCiAgICBtdXRhdGUobGFiZWwgPSBnc3ViKCIpLioiLCIiLGxhYmVsKSkKICAKICBwbHRfcmVwZWwgPC0gcGx0X2RmICU+JSAKICAgIGdncGxvdChhZXMoeD14LHk9eSxjb2xvcj1sYWJlbCkpICsKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkrCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YT1wbHRfY2VudGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbD1sYWJlbCwgIGJnLmNvbG9yPSJ3aGl0ZSIsIGJnLnI9MC4yNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiKSArCiAgICB0aGVtZV9idygpICsKICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAyKSApICkgKwogICAgbGFicyh4PXhfdmFyLCB5ID0geV92YXIsIGNvbG9yID0gY29sb3JfdmFyKSArCiAgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpCiAgcmV0dXJuKHBsdF9yZXBlbCkKfQoKcGx0X3NydCA8LSBzcnQgJT4lIAogIGZpbHRlcihjZWxsdHlwZSAlaW4lIGNlbGxzKSAlPiUgCiAgZmlsdGVyKHNhbXBsZUlEID09ICJJTkNPVjA2OS1CTCIpICU+JSAKICBnZ19zcnRfcmVsYWJlbCh4X3ZhciA9ICJVTUFQXzEiLCB5X3ZhciA9ICJVTUFQXzIiLCBjb2xvcl92YXIgPSAiY2VsbHR5cGUiLCBjZWxsX2ZyYWN0aW9uID0gMC4xKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSsgCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpKSArCiAgbGFicyh4PSJVTUFQIDEiLCB5ID0gIlVNQVAgMiIsIGNvbG9yID0gIkNlbGwgQ2x1c3RlciIpCnBsdF9zcnQKYGBgCiMjIyBBbGxlbGUgZnJlcXVlbmN5CgpgYGB7cn0KIyBzYW1wIDwtICJJTkNPVjA2OS1CTCIKIyBzYW1wIDwtICJJTkNPVjAyMi1CTCIKIyBzYW1wIDwtICJJTkNPVjA4My1CTCIKc2FtcCA8LSAiSU5DT1YwMjgtQkwiCmdlbmVfc2VsZWN0IDwtICJBIgpzY0hMQWNvdW50X2RpciA8LSBzcHJpbnRmKCIlcy9zY0hMQWNvdW50IiwgaXNiX3BhdGgpCgojIENyZWF0ZSB0aWJibGUgb2YgYWxsIGdlbm90eXBlciBhbmQgc2FtcGxlIGNvbWJpbmF0aW9ucwphbGxlbGVfZGF0YSA8LSBleHBhbmRfZ3JpZCgKICBnZW5vdHlwZXIgPSBjKCJpbnZpdHJvIiwgImFyY2FzSExBIiwgIm9wdGl0eXBlIiwgInBobGF0IiwgImhsYW1pbmVyIiksCiAgc2FtcGxlID0gcmVhZF9saW5lcyhoZXJlKCJkYXRhL2lzYi9zY0hMQWNvdW50L0JMX2Zhc3RxX2ZpbGVzLnR4dCIpKSkgJT4lIAogIGZpbHRlcihncmVwbChzYW1wLCBzYW1wbGUpKSAlPiUgCiAgIyBJbXBvcnQgZGF0YSBiYXNlZCBvbiBzYW1wbGUgYW5kIGdlbm90eXBlcgogIG11dGF0ZShyZXN1bHRfcGF0aCA9IHNwcmludGYoIiVzL3NjSExBY291bnQvb3V0cHV0X2FzZS8lcyIsaXNiX3BhdGgsIGdlbm90eXBlciksCiAgICAgICAgIGJhcmNvZGVfcGF0aCA9IHNwcmludGYoIiVzL3NjSExBY291bnQvYmFyY29kZXMiLCBpc2JfcGF0aCkpICU+JSAKICBtdXRhdGUoZGF0YSA9IHBtYXAobGlzdChzYW1wbGUsIHJlc3VsdF9wYXRoLCBiYXJjb2RlX3BhdGgpLCBmdW5jdGlvbihzLHIsYil7CiAgICBkZiA8LSBzY0hMQV9kYXRhX3Byb2Nlc3NpbmcoCiAgICAgIHNhbXBsZT1zLAogICAgICByZXN1bHRfZGlyPXIsCiAgICAgIGJhcmNvZGVfZGlyPWIKICAgICkgCiAgfSkpICU+JSB1bm5lc3QoZGF0YSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA2fQphbGxlbGVfZGF0YV9yYXRpb3MgPC0gYWxsZWxlX2RhdGEgJT4lIAogIGZpbHRlcihnZW5lID09IGdlbmVfc2VsZWN0KSAlPiUgCiAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSkgJT4lIAogIG11dGF0ZShhbGxlbGVfb3JkZXIgPSBmY3RfcmVjb2RlKGZhY3RvcihhbGxlbGVfb3JkZXIpLCAiQWxsZWxlIDEiID0gIjEiLCAiQWxsZWxlIDIiID0gIjIiKSkKICAKYWxsZWxlX2xhYmVsIDwtIGFsbGVsZV9kYXRhX3JhdGlvcyAlPiUgCiAgc2VsZWN0KGdlbm90eXBlciwgYWxsZWxlX29yZGVyLCBhbGxlbGUpICU+JSAKICBkaXN0aW5jdCgpCgpwbHQgPC0gc3J0ICU+JSAKICBsZWZ0X2pvaW4oYWxsZWxlX2RhdGFfcmF0aW9zICU+JSBmaWx0ZXIoZ2VuZSA9PSBnZW5lX3NlbGVjdCksIGJ5ID0gImNlbGwiKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShhbGxlbGUpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBjb2xvciA9IGFsbGVsZV9yYXRpbykpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjUsIGFscGhhID0gMC41KSsKICB0aGVtZV9idygpICsKICBmYWNldF9ncmlkKGFsbGVsZV9vcmRlcn5nZW5vdHlwZXIpKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50MihoaWdoID0gInJlZCIsIG1pZCA9ICJncmV5ODAiLCBsb3cgPSAiYmx1ZSIsIG1pZHBvaW50ID0gMC41LCBuYS52YWx1ZSA9ICJ0cmFuc3BhcmVudCIpICsKICBsYWJzKHg9IlVNQVAgMSIsIHk9IlVNQVAgMiIsIGNvbG9yID0gIkFsbGVsZSBcbkZyZXF1ZW5jeSIpKwogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xMCwxNSkpCgpwbHRfYWxsZWxlX2ZyZXEgPC0gcGx0KwogIGdlb21fbGFiZWwoZGF0YSA9IGFsbGVsZV9sYWJlbCwgYWVzKHg9LTEwLHk9MTQsIGNvbG9yID0gTlVMTCwgbGFiZWwgPSBhbGxlbGUpLCBzaXplID0gMywgaGp1c3QgPSAwKQoKcGx0X2FsbGVsZV9mcmVxCmBgYAoKIyMjIE1heGltdW0gYWxsZWxlCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSAzLCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CiMgQ3JlYXRlIHRpYmJsZSBvZiBhbGwgZ2Vub3R5cGVyIGFuZCBzYW1wbGUgY29tYmluYXRpb25zCmFsbGVsZV9tYXhfcmF0aW8gPC0gYWxsZWxlX2RhdGEgICU+JQogIHNlbGVjdChnZW5vdHlwZXIsIGNlbGwsIGdlbmUsIGFsbGVsZV9vcmRlciwgYWxsZWxlX3JhdGlvKSAlPiUKICAjIGdyb3VwX2J5KGdlbm90eXBlciwgY2VsbCwgYWxsZWxlX29yZGVyKSAlPiUgIG11dGF0ZSh0ZXN0ID0gbGVuZ3RoKGFsbGVsZV9vcmRlcikpCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJhbGxlbGVfb3JkZXIiLCB2YWx1ZXNfZnJvbSA9ICJhbGxlbGVfcmF0aW8iLCBuYW1lc19wcmVmaXggPSAiYWxsZWxlXyIpICU+JQogIHJvd3dpc2UoKSAlPiUKICBtdXRhdGUobWF4X3JhdGlvID0gbWF4KGFjcm9zcyhjb250YWlucygiYWxsZWxlXyIpKSwgbmEucm0gPSBUKSkgJT4lCiAgc2VsZWN0KGdlbm90eXBlciwgY2VsbCwgZ2VuZSwgbWF4X3JhdGlvKSAlPiUKICBmaWx0ZXIoZ2VuZSA9PSBnZW5lX3NlbGVjdCkgCgphbGxlbGVfbGFiZWwgPC0gYWxsZWxlX2RhdGEgJT4lIHNlbGVjdChzYW1wbGUsIGdlbm90eXBlciwgZ2VuZSwgYWxsZWxlKSAlPiUgCiAgZmlsdGVyKGdlbmUgPT0gZ2VuZV9zZWxlY3QpICU+JSAKICBzZXBhcmF0ZShzYW1wbGUsIGludG8gPSBjKCJzYW1wbGUiLCBOVUxMKSwgc2VwID0gIl8iLCBleHRyYSA9ICJkcm9wIikgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSwgZ2Vub3R5cGVyLCBnZW5lKSAlPiUgbmVzdCgpICU+JSB1bm5lc3Rfd2lkZXIoZGF0YSkgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAKICBtdXRhdGUoYWxsZWxlID0gbWFwX2NocihhbGxlbGUsIHBhc3RlLCBjb2xsYXBzZSA9ICJcbiIpKQoKcGx0X21heF9hbGxlbGUgPC0gc3J0ICU+JSAKICBsZWZ0X2pvaW4oYWxsZWxlX21heF9yYXRpbyAlPiUgZmlsdGVyKGdlbmUgPT0gZ2VuZV9zZWxlY3QpLCBieSA9ICJjZWxsIikgJT4lIAogICMgbXV0YXRlKGdlbm90eXBlciA9IGZjdF9yZWxldmVsKGdlbm90eXBlciwgImludml0cm8iKSkgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKGdlbm90eXBlcikpICU+JQogIGdncGxvdChhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3IgPSBtYXhfcmF0aW8pKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAwLjUsIGFscGhhID0gMC41KSsKICAgIGdlb21fbGFiZWwoZGF0YSA9IGFsbGVsZV9sYWJlbCwgYWVzKGNvbG9yID0gTlVMTCwgbGFiZWwgPSBhbGxlbGUsIHggPSAtSW5mLCB5ID0gLUluZiksCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgdmp1c3QgPSAtMC4xLCBzaXplID0gMywgaGp1c3QgPSAwKSArCiAgICB0aGVtZV9idygpICsKICAgIGZhY2V0X2dyaWQoLn5nZW5vdHlwZXIpKwogICAgc2NhbGVfY29sb3JfZ3JhZGllbnQoaGlnaCA9ICJyZWQiLCBsb3cgPSAiYmx1ZSIsIG5hLnZhbHVlID0gInRyYW5zcGFyZW50IikgKwogICAgbGFicyh4PSJVTUFQIDEiLCB5PSJVTUFQIDIiLCBjb2xvciA9ICJNYXhpbXVtIEFsbGVsZSBcbkZyZXF1ZW5jeSIpKwogICAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKQoKcGx0X21heF9hbGxlbGUgCmBgYAoKIyBNZXRhLWFuYWx5c2lzIGFwcHJvYWNoCgojIyMgUmF0aW9uYWxlIAoKLSBHb2FsOiBkZXRlcm1pbmUgYSBzdW1tYXJ5IHN0YXRpc3RpYyBmb3IgYWxsZWxlIHJhdGlvIGFjcm9zcyBhbGwgY2VsbHMKLSBQcm9ibGVtOgogIC0gRWFjaCBjZWxsIGluIHNjUk5BIGV4cGVyaW1lbnQgaGFzIGl0cyBvd24gcmF0aW8gb2YgSExBIGFsbGVsZSAxIHJlYWRzIDogSExBIGFsbGVsZSAyIHJlYWRzCiAgLSBBIHdpZGUgcmFuZ2Ugb2YgdG90YWwgcmVhZCBjb3VudHMgbWF5IGdvIGludG8gZWFjaCBjZWxsJ3MgcmF0aW8KICAtIFNtYWxsIGRpZmZlcmVuY2UgaW4gcmVhZCBjb3VudHMgZm9yIGNlbGxzIHdpdGggbG93IHRvdGFsIHJlYWRzIGNhbiBncmVhdGx5IGFsdGVyIHRoZSBhbGxlbGUgcmF0aW8gY29tcGFyZWQgdG8gY2VsbHMgd2l0aCBoaWdoIHRvdGFsIHJlYWQgY291bnRzCiAgICAtIEkuZS4gQ2VsbHMgd2l0aCBsb3cgcmVhZCBjb3VudHMgYXJlIG1vcmUgbGlrZWx5IHRvIGhhdmUgaW1wcmVjaXNlIGFsbGVsZSByYXRpb3MKICAtIFNpbXBseSBhdmVyYWdpbmcgcmF0aW9zIHdvdWxkIGVxdWFsbHkgd2VpZ2h0IGhpZ2ggY29uZmlkZW5jZSwgaGlnaCByZWFkIGNvdW50IHJhdGlvcyB3aXRoIGxvdyBjb25maWRlbmNlLCBsb3cgcmVhZCByYXRpb3MKLSBBcHByb2FjaAogIC0gTWV0YS1hbmFseXNpcyBtZXRob2RzIHNwZWNpZmljYWxseSBhZGRyZXNzIHR5cGUgb2YgcHJvYmxlbSwgdHlwaWNhbGx5IGJ5IHdlaWdoaW5nIGFuIGVmZmVjdCBieSB0aGUgaW52ZXJzZSBvZiBpdHMgdmFyaWFuY2UKICAtIEluIHRoZSBzZXR0aW5nIG9mIHJhdGlvcywgYmFzaWMgYXBwcm9hY2ggd291bGQgYmUgdG8gY29tYmluZSBsb2ctb2RkcyByYXRpbyBvZiBhbGxlbGVzLCB3ZWlnaHRlZCBieSBpbnZlcnNlIHZhcmlhbmNlCiAgLSBXb3VsZCB1c2UgYSByYW5kb20gZWZmZWN0cyBtb2RlbCBiZWNhdXNlIGRvIG5vdCBleHBlY3QgZWFjaCBjZWxsIGluIGEgZ3JvdXAgd291bGQgaGF2ZSB0aGUgc2FtZSBleGFjdCByYXRpbyBkdWUgdG8gdmFyaW91cyBzdG9jaGFzdGljIHRyYW5zY3JpcHRpb25hbCBlZmZlY3RzCgojIyMgQ2FsY3VsYXRpbmcgc3VtbWFyeSBlZmZlY3Qgc2l6ZXMKCi0gQW5hbHlzaXMgY2FuIHRha2Ugc29tZSB0aW1lLCBzbyBydW4gb24gYW4gSFBDIGNsdXN0ZXIgdXNpbmcgc2x1cm0KLSBDb250YWluZWQgaW4gYSBzZXBhcmF0ZSBzY3JpcHQgYHNjX21ldGEuUmA6CgojIyMjIENvbnRlbnRzIG9mIGBzY19tZXRhLlJgCgpgYGB7ciwgZXZhbCA9IEZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1ldGEpCgpzb3VyY2UoaGVyZSgiaGVscGVyX2Z1bmN0aW9ucy9kYXRhX2ltcG9ydF9mdW5jdGlvbnMuUiIpKQppc2JfcGF0aCA8LSBoZXJlKCJkYXRhL2lzYiIpCgpzcnQgPC0gcmVhZFJEUyhoZXJlKCJkYXRhL2lzYi9pc2Jfc2NfbWV0YWRhdGEuUkRTIikpCmNlbGxzIDwtIGMoIkNEMTQgTW9ub2N5dGUiLCAiQ0Q0IFQiLCAiQ0Q4IFQiLCAiTksiLCAiQiIsICJDRDE2IE1vbm9jeXRlIiwgImNEQyIsICJwREMiKQpzcnQgPC0gc3J0ICU+JSBzZWxlY3Qoc2FtcGxlLCBzYW1wbGVJRCwgY2VsbCwgY2VsbHR5cGUsIHNldmVyaXR5LCBVTUFQXzEsIFVNQVBfMikgJT4lIAogIGZpbHRlcihjZWxsdHlwZSAlaW4lIGNlbGxzKQoKIyBGdW5jdGlvbiB0byBwZXJmb3JtIG1ldGEtYW5hbHlzaXMgb24gZGF0YWZyYW1lIHdoZXJlCiMgZWFjaCByb3cgaXMgYSBjZWxsIGFuZCBjb2x1bW5zOgojIGBvYnNlcnZlZGAgKHJlYWRzIG9mIGRvbWluYW50IGFsbGVsZSkKIyBgZ2VuZV9zdW1fdHlwZWRgICh0b3RhbCBjZWxsIHJlYWRzKQojIGBleHBlY3RlZGAgKHJlYWRzIG9mIG9uZSBhbGxlbGUgZXhwZWN0ZWQgaWYgNTA6NTAgYWxsZWxlXzEgOiBhbGxlbGVfMikKc2NfbWV0YSA8LSBmdW5jdGlvbihkZil7CiAgbCA8LSBucm93KGRmKQogIG0gPC0gbWV0YWJpbihldmVudC5lID0gb2JzZXJ2ZWQsIG4uZSA9IGdlbmVfc3VtX3R5cGVkLCBldmVudC5jID0gZXhwZWN0ZWQsIG4uYyA9IGdlbmVfc3VtX3R5cGVkLAogICAgICAgICAgICAgICBkYXRhID0gZGYsCiAgICAgICAgICAgICAgIG1ldGhvZCA9ICJJbnZlcnNlIiwKICAgICAgICAgICAgICAgaW5jciA9IDAuMSwKICAgICAgICAgICAgICAgc20gPSAiT1IiKQogIGRhdGEuZnJhbWUoc3VtbWFyeShtKSRyYW5kb20pICU+JSAKICAgIG11dGF0ZShuX2NlbGxzID0gbCkgJT4lIAogICAgc2VsZWN0KFRFLCBzZVRFLCBsb3dlciwgdXBwZXIsIG5fY2VsbHMpIAp9CgojIEltcG9ydCBkYXRhIGJhc2VkIG9uIHNhbXBsZSBhbmQgZ2Vub3R5cGVyCmNlbGxfc3RhdHMgPC0gZXhwYW5kX2dyaWQoCiAgZ2Vub3R5cGVyID0gYygiaW52aXRybyIsICJhcmNhc0hMQSIsICJvcHRpdHlwZSIsICJwaGxhdCIsICJobGFtaW5lciIpLAogIHNhbXBsZSA9IHJlYWRfbGluZXMoaGVyZSgiZGF0YS9pc2Ivc2NITEFjb3VudC9CTF9mYXN0cV9maWxlcy50eHQiKSkpICU+JSAKICAjIGhlYWQoNSkgJT4lICMgU3BlY2lmeSBsaW1pdCB0byBudW1iZXIgb2YgbWV0YS1hbmFseXNlcwogIG11dGF0ZShkYXRhID0gbWFwMihzYW1wbGUsIGdlbm90eXBlciwgZnVuY3Rpb24ocyxnKXsKICAgIHJlc3VsdF9wYXRoID0gc3ByaW50ZigiJXMvc2NITEFjb3VudC9vdXRwdXRfYXNlLyVzIixpc2JfcGF0aCwgZykKICAgIGJhcmNvZGVfcGF0aCA9IHNwcmludGYoIiVzL3NjSExBY291bnQvYmFyY29kZXMiLCBpc2JfcGF0aCkKICAgIHNjSExBX2RhdGFfcHJvY2Vzc2luZyhzYW1wbGUgPSBzLAogICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdF9kaXIgPSByZXN1bHRfcGF0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJjb2RlX2RpciA9IGJhcmNvZGVfcGF0aCkKICB9KSkgJT4lIHVubmVzdChkYXRhKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShjZWxsKSkgJT4lIAogIG11dGF0ZShzYW1wbGUgPSBnc3ViKCJfW0EtWl1bMC05XSQiLCIiLHNhbXBsZSkpICU+JSAjIENvbnNvbGlkYXRlIHNhbXBsZXMKICBsZWZ0X2pvaW4oc3J0ICU+JSBzZWxlY3QoY2VsbHR5cGUsIGNlbGwpLCBieSA9ICJjZWxsIikgJT4lICMgQWRkIGNlbGx0eXBlcwogIGZpbHRlcihjZWxsdHlwZSAlaW4lIGNlbGxzKSAjIEtlZXAgb25seSBzdGFuZGFyZCBjZWxsIHR5cGVzCgptZXRhX2RmIDwtIGNlbGxfc3RhdHMgJT4lIAogICMgS2VlcCBvbmx5IG1vc3QgZXhwcmVzc2VkIGFsbGVsZSAob3IgcmFuZG9tIGlmIDUwOjUwKQogIGdyb3VwX2J5KHNhbXBsZSwgZ2Vub3R5cGVyLCBnZW5lLCBjZWxsKSAlPiUgCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gYWxsZWxlX3JhdGlvLCBuID0gMSwgd2l0aF90aWVzID0gRikgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgIyBGaWxsIG91dCBjb250aW5nZW5jeSB0YWJsZQogIG11dGF0ZShjb21wbGVtZW50ID0gZ2VuZV9zdW1fdHlwZWQgLSBjb3VudCwgCiAgICAgICAgIGV4cGVjdGVkID0gMC41KmdlbmVfc3VtX3R5cGVkKSAlPiUgCiAgcmVuYW1lKG9ic2VydmVkID0gY291bnQpICU+JSAKICBzZWxlY3Qoc2FtcGxlLCBnZW5vdHlwZXIsIGNlbGx0eXBlLCBnZW5lLCBvYnNlcnZlZCwgZXhwZWN0ZWQsIGdlbmVfc3VtX3R5cGVkKSAlPiUgCiAgZ3JvdXBfYnkoc2FtcGxlLCBnZW5vdHlwZXIsIGNlbGx0eXBlLCBnZW5lKSAlPiUKICAjIE5lc3QgYW5kIHJ1biBtZXRhLWFuYWx5c2lzCiAgbmVzdCgpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKGRhdGEgPSBtYXAoZGF0YSxmdW5jdGlvbih4KSB7c2NfbWV0YSh4KX0pKSAlPiUKICB1bm5lc3QoZGF0YSkKCndyaXRlX2NzdihtZXRhX2RmLCBoZXJlKCI3X0hMQV9BU0UvbWV0YV9hbmFseXNpc19yZXN1bHRzLmNzdiIpKQpgYGAKCiMjIyBTaW5nbGUgc2FtcGxlIGFuYWx5c2lzCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9Cm1ldGFfZGYgPC0gcmVhZF9jc3YoaGVyZSgiN19ITEFfQVNFL21ldGFfYW5hbHlzaXNfcmVzdWx0cy5jc3YiKSkgCm1ldGFfZGYKYGBgCmBgYHtyfQojIFNpbmdsZSBjZWxsdHlwZSBhbmQgZ2VuZQpjZWxsX3NlbGVjdCA8LSAiTksiCnBsdF9tZXRhIDwtIG1ldGFfZGYgJT4lIAogIGZpbHRlcihzYW1wbGUgPT0gc2FtcCkgJT4lIAogIGZpbHRlcihjZWxsdHlwZSA9PSBjZWxsX3NlbGVjdCwgZ2VuZSA9PSBnZW5lX3NlbGVjdCkgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBnZW5vdHlwZXIsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIpKSsKICBnZW9tX3BvaW50KCkrCiAgZ2VvbV9lcnJvcmJhcigpKwogIHRoZW1lX2J3KCkrCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCxOQSkpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBsYWJzKHkgPSAiTG9nLU9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCkKcGx0X21ldGEKYGBgCmBgYHtyfQpzYW1wbGVzIDwtIHVuaXF1ZShtZXRhX2RmJHNhbXBsZSkKZm9yIChpIGluIDE6bGVuZ3RoKHNhbXBsZXMpKXsKcGx0X21ldGEgPC0gbWV0YV9kZiAlPiUgCiAgZmlsdGVyKHNhbXBsZSA9PSBzYW1wbGVzW2ldKSAlPiUgCiAgZmlsdGVyKGNlbGx0eXBlID09ICJDRDE0IE1vbm9jeXRlIiwgZ2VuZSA9PSAiQSIpICU+JSAKICBtdXRhdGUoZ2Vub3R5cGVyID0gcmVmb3JtYXRfaGxhX2dlbm90eXBlcihnZW5vdHlwZXIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZ2Vub3R5cGVyLCB5ID0gVEUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyKSkrCiAgZ2VvbV9wb2ludCgpKwogIGdlb21fZXJyb3JiYXIoKSsKICB0aGVtZV9idygpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsTkEpKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgbGFicyh5ID0gIkxvZy1PZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwpICsKICBnZ3RpdGxlKHNhbXBsZXNbaV0pCiAgcHJpbnQocGx0X21ldGEpCn0KYGBgCgoKCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDR9CiMgQWxsIGNlbGx0eXBlcyBhbmQgZ2VuZXMKbWV0YV9kZiAlPiUgCiAgbXV0YXRlKAogICAgY2VsbHR5cGUgPSBmYWN0b3IoY2VsbHR5cGUsIGxldmVscyA9IGMoCiAgICAiY0RDIiwgIkNEMTQgTW9ub2N5dGUiLCAiQiIsICJwREMiLCAiQ0QxNiBNb25vY3l0ZSIsICJDRDggVCIsICJDRDQgVCIsICJOSyIpKSkgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAKICBtdXRhdGUoZ2VuZSA9IHJlZm9ybWF0X2hsYV9sb2NpKGdlbmUpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY2VsbHR5cGUsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIsIGZpbGwgPSBjZWxsdHlwZSkpKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yNSkrCiAgICBnZW9tX2Vycm9yYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgd2lkdGggPTAuNSkrCiAgICB0aGVtZV9idygpKwogICAgZmFjZXRfZ3JpZChnZW5lfmdlbm90eXBlciwgc2NhbGVzID0gImZyZWVfeSIpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogICAgbGFicyh5ID0gIkxvZy1PZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwsIGZpbGwgPSAiQ2VsbCB0eXBlIikgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCgptZXRhX2RmICU+JSAKICBtdXRhdGUoCiAgICBjZWxsdHlwZSA9IGZhY3RvcihjZWxsdHlwZSwgbGV2ZWxzID0gYygKICAgICJjREMiLCAiQ0QxNCBNb25vY3l0ZSIsICJCIiwgInBEQyIsICJDRDE2IE1vbm9jeXRlIiwgIkNEOCBUIiwgIkNENCBUIiwgIk5LIikpKSAlPiUgCiAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSkgJT4lIAogIG11dGF0ZShnZW5lID0gcmVmb3JtYXRfaGxhX2xvY2koZ2VuZSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBnZW5vdHlwZXIsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIsIGZpbGwgPSBjZWxsdHlwZSkpKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yNSkrCiAgICBnZW9tX2Vycm9yYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgd2lkdGggPTAuNSkrCiAgICB0aGVtZV9idygpKwogICAgZmFjZXRfZ3JpZChnZW5lfmNlbGx0eXBlLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgICBsYWJzKHkgPSAiTG9nLU9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCwgZmlsbCA9ICJDZWxsIHR5cGUiKSArCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKYGBgCgoKCiMjIyBNdWx0aS1zYW1wbGUgYW5hbHlzaXMKCmBgYHtyLCBtZXNzYWdlID0gRn0KbWV0YV9kZiA8LSByZWFkX2NzdihoZXJlKCI3X0hMQV9BU0UvbWV0YV9hbmFseXNpc19yZXN1bHRzLmNzdiIpKSAlPiUgCiAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSwKICAgICAgICAgY2VsbHR5cGUgPSBmYWN0b3IoY2VsbHR5cGUsIGxldmVscyA9IGMoCiAgICAgICAgICAiY0RDIiwgIkNEMTQgTW9ub2N5dGUiLCAiQiIsICJwREMiLCAiQ0QxNiBNb25vY3l0ZSIsICJDRDggVCIsICJDRDQgVCIsICJOSyIpKSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA2LCB3YXJuaW5nID0gRn0KbWV0YV9kZiAlPiUgCiAgZ2dwbG90KGFlcyh4PWNlbGx0eXBlLHk9VEUsIGZpbGwgPSBjZWxsdHlwZSkpKwogIGdlb21fdmlvbGluKCkrCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjIsIHNpemUgPSAwLjIpKwogIHN0YXRfc3VtbWFyeShmdW49bWVhbiwgc3RhdD0gInBvaW50IikrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbT0iZXJyb3JiYXIiKSsKICBmYWNldF9ncmlkKGdlbmV+Z2Vub3R5cGVyKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBsYWJzKHkgPSAiTG9nLU9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCwgZmlsbCA9ICJDZWxsIHR5cGUiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCgptZXRhX2RmICU+JSAKICBnZ3Bsb3QoYWVzKHg9Z2Vub3R5cGVyLHk9VEUsIGZpbGwgPSBjZWxsdHlwZSkpKwogIGdlb21fdmlvbGluKCkrCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjIsIHNpemUgPSAwLjIpKwogIHN0YXRfc3VtbWFyeShmdW49bWVhbiwgc3RhdD0gInBvaW50IikrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbT0iZXJyb3JiYXIiKSsKICBmYWNldF9ncmlkKGdlbmV+Y2VsbHR5cGUpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogIGxhYnMoeSA9ICJMb2ctT2RkcyByYXRpbyBvZiBkb21pbmFudCBhbGxlbGUiLCB4PSBOVUxMLCBmaWxsID0gIkNlbGwgdHlwZSIpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKYGBgCgojIyMgQ29ycmVsYXRpb24gYW5hbHlzaXMKCmBgYHtyLCBtZXNzYWdlID0gRiwgd2FybmluZz1GfQptZXRhX2RmICU+JSAKICBmaWx0ZXIoZ2VuZSA9PSAiQSIsIGNlbGx0eXBlID09ICJjREMiKSAlPiUgCiAgc2VsZWN0KHNhbXBsZSwgZ2Vub3R5cGVyLCBURSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiZ2Vub3R5cGVyIiwgdmFsdWVzX2Zyb20gPSAiVEUiKSAlPiUgCiAgc2VsZWN0KC1zYW1wbGUpICU+JSAKICBHR2FsbHk6OmdncGFpcnMocHJvZ3Jlc3MgPSBGQUxTRSkgKwogIHRoZW1lX2J3KCkKYGBgCgpgYGB7ciwgbWVzc2FnZSA9IEYsIHdhcm5pbmc9Rn0KYWNjdXJhY3lfZGYgPC0gcmVhZFJEUyhoZXJlKCIzX0RSQi9pc2JfYWNjdXJhY3lfZHJiMzQ1X2ZpbHRlcmVkLlJEUyIpKSAlPiUgCiAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSkgJT4lIAogIHNlbGVjdChzYW1wbGUsIGdlbmU9bG9jdXMsIGdlbm90eXBlciwgYWNjdXJhY3kpICU+JSAKICBkaXN0aW5jdCgpCmZvciAoaSBpbiBjKDAsMSkpewogIHN1cHByZXNzV2FybmluZ3MoewogIHBsdCA8LSBtZXRhX2RmICU+JSAKICAgIHVuZ3JvdXAoKSAlPiUgCiAgICBmaWx0ZXIoZ2VuZSA9PSAiQSIsIGNlbGx0eXBlID09ICJjREMiKSAlPiUgCiAgICBsZWZ0X2pvaW4oYWNjdXJhY3lfZGYsIGJ5ID0gYygic2FtcGxlIiwgImdlbmUiLCAiZ2Vub3R5cGVyIikpICU+JSAKICAgIGZpbHRlcihhY2N1cmFjeSA9PSBpIHwgZ2Vub3R5cGVyID09ICJHcm91bmQgdHJ1dGgiKSAlPiUgCiAgICAjIGRyb3BfbmEoYWNjdXJhY3kpICU+JSAKICAgIHNlbGVjdChzYW1wbGUsIGdlbm90eXBlciwgVEUpICU+JSAKICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiZ2Vub3R5cGVyIiwgdmFsdWVzX2Zyb20gPSAiVEUiKSAlPiUgCiAgICBzZWxlY3QoLXNhbXBsZSkgJT4lIAogICAgR0dhbGx5OjpnZ3BhaXJzKHByb2dyZXNzID0gRkFMU0UpICsKICAgIHRoZW1lX2J3KCkgKwogICAgZ2d0aXRsZShzcHJpbnRmKCJDb3JyZWxhdGlvbiBvZiBhbGxlbGUgcmF0aW9zIHdoZXJlIGFjY3VyYWN5ID0gJXMiLCBpKSkKICBwcmludChwbHQpCiAgfSkKfQpgYGAKCmBgYHtyLCB3YXJuaW5nID0gRn0KY29ycl9kZiA8LSBtZXRhX2RmICU+JSAKICBtdXRhdGUoZ2Vub3R5cGVyID0gcmVmb3JtYXRfaGxhX2dlbm90eXBlcihnZW5vdHlwZXIpKSAlPiUgCiAgc2VsZWN0KHNhbXBsZSwgZ2Vub3R5cGVyLCBjZWxsdHlwZSwgZ2VuZSwgVEUpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gImdlbm90eXBlciIsIHZhbHVlc19mcm9tID0gIlRFIikgJT4lIAogIHBpdm90X2xvbmdlcihjKGFyY2FzSExBLCBITEFtaW5lciwgT3B0aVR5cGUsIFBITEFUKSwgbmFtZXNfdG8gPSAiZ2Vub3R5cGVyIiwgdmFsdWVzX3RvID0gIlRFIikgJT4lIAogIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpCmNvcnJfZGYgJT4lIAogIGdncGxvdChhZXMoeD1gR3JvdW5kIHRydXRoYCwgeT1URSkpKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkrCiAgZmFjZXRfZ3JpZChnZW5lIH4gZ2Vub3R5cGVyKSArCiAgdGhlbWVfYncoKSArCiAgZ2dwdWJyOjpzdGF0X2NvcihhZXMobGFiZWwgPSAuLnJyLmxhYmVsLi4pLCBsYWJlbC54Lm5wYyA9ICJsZWZ0IiwgbGFiZWwueS5ucGMgPSAidG9wIiwgZ2VvbSA9ICJsYWJlbCIpCmBgYAoKYGBge3J9CmZvciAoaSBpbiBjKDAsMSkpewogIHN1cHByZXNzV2FybmluZ3MoewogIHBsdCA8LSBjb3JyX2RmICU+JSAKICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAjIGZpbHRlcihnZW5lID09ICJBIiwgY2VsbHR5cGUgPT0gImNEQyIpICU+JSAKICAgIGxlZnRfam9pbihhY2N1cmFjeV9kZiwgYnkgPSBjKCJzYW1wbGUiLCAiZ2VuZSIsICJnZW5vdHlwZXIiKSkgJT4lIAogICAgZmlsdGVyKGFjY3VyYWN5ID09IGkpICU+JSAKICAgIGdncGxvdChhZXMoeD1gR3JvdW5kIHRydXRoYCwgeT1URSkpKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41KSsKICAgIGZhY2V0X2dyaWQoZ2VuZSB+IGdlbm90eXBlcikgKwogICAgdGhlbWVfYncoKSArCiAgICBnZ3B1YnI6OnN0YXRfY29yKGFlcyhsYWJlbCA9IC4ucnIubGFiZWwuLiksIGxhYmVsLngubnBjID0gImxlZnQiLCBsYWJlbC55Lm5wYyA9ICJ0b3AiLCBnZW9tID0gImxhYmVsIikgKwogICAgICBnZ3RpdGxlKHNwcmludGYoIkNvcnJlbGF0aW9uIG9mIGFsbGVsZSByYXRpb3Mgd2hlcmUgYWNjdXJhY3kgPSAlcyIsIGkpKSArCiAgICBsYWJzKHkgPSAiUHJlZGljdGVkIGdlbm90eXBlIEhMQSBhbGxlbGUgbG9nLW9kZHMgcmF0aW8iLCB4ID0gIkdyb3VuZCB0cnV0aCBnZW5vdHlwZSBITEEgYWxsZWxlIGxvZy1vZGRzIHJhdGlvIikKICBhc3NpZ24oc3ByaW50ZigicGx0X21ldGFfY29ycl8lcyIsIGkpLCBwbHQpCiAgcHJpbnQocGx0KQogIH0pCn0KCmBgYApgYGB7cn0KcGx0X21ldGFfY29ycl9hYmJyZXYgPC0gY29ycl9kZiAlPiUgCiAgbGVmdF9qb2luKGFjY3VyYWN5X2RmLCBieSA9IGMoInNhbXBsZSIsICJnZW5lIiwgImdlbm90eXBlciIpKSAlPiUgCiAgZmlsdGVyKGdlbmUgPT0gIkEiLCBhY2N1cmFjeSAlaW4lIGMoMCwwLjUsMSkpICU+JQogIGdncGxvdChhZXMoeD1gR3JvdW5kIHRydXRoYCwgeT1URSkpKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41KSsKICAgIGZhY2V0X2dyaWQoYWNjdXJhY3kgfiBnZW5vdHlwZXIsIGxhYmVsbGVyID0gbGFiZWxsZXIoYWNjdXJhY3kgPSBmdW5jdGlvbih4KSBzcHJpbnRmKCJBY2N1cmFjeTogJXMiLCB4KSkpICsKICAgIHRoZW1lX2J3KCkgKwogICAgZ2dwdWJyOjpzdGF0X2NvcihhZXMobGFiZWwgPSAuLnJyLmxhYmVsLi4pLCBsYWJlbC54Lm5wYyA9ICJsZWZ0IiwgbGFiZWwueS5ucGMgPSAidG9wIiwgZ2VvbSA9ICJsYWJlbCIsIG1ldGhvZCA9ICJwZWFyc29uIikgKwogICAgbGFicyh5ID0gIkxvZy1vZGRzIHJhdGlvIHVzaW5nIHByZWRpY3RlZCBnZW5vdHlwZSIsIHggPSAiTG9nLW9kZHMgcmF0aW8gdXNpbmcgZ3JvdW5kIHRydXRoIGdlbm90eXBlciIpCnBsdF9tZXRhX2NvcnJfYWJicmV2CmBgYApgYGB7cn0KYWNjdXJhY3lfZGYgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBjb3VudChnZW5lLCBnZW5vdHlwZXIsIGFjY3VyYWN5KQpgYGAKCgoKIyMjIEJ5IHNldmVyaXR5CgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA2LCB3YXJuaW5nID0gRn0KbWV0YV9kZiAlPiUgCiAgZmlsdGVyKGdlbm90eXBlciA9PSAiR3JvdW5kIHRydXRoIikgJT4lIAogIGxlZnRfam9pbigKICAgIHNydCAlPiUgCiAgICAgIHNlbGVjdChzYW1wbGUgPSBzYW1wbGVJRCwgc2V2ZXJpdHkpICU+JSAKICAgICAgZGlzdGluY3QoKSwKICAgIGJ5ID0gInNhbXBsZSIKICApICU+JSAKICBnZ3Bsb3QoYWVzKHg9c2V2ZXJpdHkseT1URSwgZmlsbCA9IGNlbGx0eXBlKSkrCiAgICBnZW9tX3Zpb2xpbigpKwogICAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjIsIHNpemUgPSAwLjIpKwogICAgc3RhdF9zdW1tYXJ5KGZ1bj1tZWFuLCBzdGF0PSAicG9pbnQiKSsKICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsIGdlb209ImVycm9yYmFyIikrCiAgICBmYWNldF9ncmlkKGdlbmV+Y2VsbHR5cGUpKwogICAgdGhlbWVfYncoKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICAgIGxhYnMoeSA9ICJMb2ctT2RkcyByYXRpbyBvZiBkb21pbmFudCBhbGxlbGUiLCB4PSBOVUxMLCBmaWxsID0gIkNlbGwgdHlwZSIpICsKICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKQpgYGAKCmBgYHtyfQptZXRhX2RmICU+JSAKICBmaWx0ZXIoZ2Vub3R5cGVyID09ICJHcm91bmQgdHJ1dGgiKSAlPiUgCiAgbGVmdF9qb2luKAogICAgc3J0ICU+JSAKICAgICAgc2VsZWN0KHNhbXBsZSA9IHNhbXBsZUlELCBzZXZlcml0eSkgJT4lIAogICAgICBkaXN0aW5jdCgpLAogICAgYnkgPSAic2FtcGxlIgogICkgJT4lIAogIG11dGF0ZShzZXZlcml0eSA9IGFzLm51bWVyaWMoc2V2ZXJpdHkpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc2V2ZXJpdHksIHkgPSBURSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iKSsKICBmYWNldF93cmFwKH5jZWxsdHlwZSkrCiAgdGhlbWVfYncoKSAKYGBgCgojIFBsb3RzIGZvciBmaWd1cmVzCgojIEFzc2VtYmxlIHBsb3QKYGBge3IsIGZpZy53aWR0aCA9IDE0LCBmaWcuaGVpZ2h0ID0gMTB9CiMgcGx0X2FsbGVsZV9mcmVxX2xnZCA8LSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9hbGxlbGVfZnJlcSkKIyBwbHRfbWF4X2FsbGVsZV9sZ2QgPC0gY293cGxvdDo6Z2V0X2xlZ2VuZChwbHRfbWF4X2FsbGVsZSkKY29sXzEgPC0gcGxvdF9ncmlkKAogIHBsdF9hbGxlbGVfZnJlcSwKICBwbHRfbWF4X2FsbGVsZSwKICBuY29sID0gMSwKICByZWxfaGVpZ2h0cyA9IGMoNSwzKSwKICBhbGlnbiA9ICJ2IiwgYXhpcyA9ICJsciIsCiAgbGFiZWxzID0gTEVUVEVSU1sxOjJdCikKCmNvbF8yIDwtIHBsb3RfZ3JpZCgKICBwbHRfc3J0LAogIHBsdF9tZXRhLAogIG5jb2wgPSAxLAogIGFsaWduID0gInYiLCBheGlzID0gImxyIiwKICBsYWJlbHMgPSBMRVRURVJTWzM6NF0sCiAgaGp1c3QgPSAwLjUKKQpyb3dfMSA8LSBwbG90X2dyaWQoCiAgY29sXzEsCiAgY29sXzIsCiAgbnJvdyA9IDEsCiAgcmVsX3dpZHRocyA9IGMoNiwzKQopCnJvd18yIDwtIHBsb3RfZ3JpZCgKICBwbHRfbWV0YV9jb3JyXzAgK2dndGl0bGUoTlVMTCksCiAgcGx0X21ldGFfY29ycl8xICtnZ3RpdGxlKE5VTEwpLAogIGxhYmVscyA9IExFVFRFUlNbNTo2XSwKICBuY29sID0gMgopCnBsb3RfZ3JpZCgKICByb3dfMSwKICByb3dfMiwKICByZWxfaGVpZ2h0cyA9IGMoMywyKSwKICBuY29sID0gMQopCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDE0LCBmaWcuaGVpZ2h0ID0gNn0KY29sXzEgPC0gcGxvdF9ncmlkKAogIHBsdF9zcnQsCiAgcGx0X21ldGEsCiAgbmNvbCA9IDEsCiAgYWxpZ24gPSAidiIsIGF4aXMgPSAibHIiLAogIGxhYmVscyA9IExFVFRFUlNbYygxLDMpXSwKICBsYWJlbF94ID0gLTAuMDUKKQoKY29sXzIgPC0gcGxvdF9ncmlkKAogIHBsdF9tYXhfYWxsZWxlLAogIHBsdF9tZXRhX2NvcnJfYWJicmV2LAogIG5jb2wgPSAxLAogIHJlbF9oZWlnaHRzID0gYygzLDUpLAogIGFsaWduID0gInYiLCBheGlzID0gImxyIiwKICBsYWJlbHMgPSBMRVRURVJTW2MoMiw0KV0sCiAgbGFiZWxfeCA9IC0wLjA1CikKCnBsdF9maWdfbWFpbiA8LSBwbG90X2dyaWQoCiAgTlVMTCwKICBjb2xfMSwKICBjb2xfMiwKICBucm93ID0gMSwKICByZWxfd2lkdGhzID0gYygwLjI1LDMsNikKKQoKcGx0X2ZpZ19tYWluCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDE0LCBmaWcuaGVpZ2h0ID0gNX0KY29sXzEgPC0gcGxvdF9ncmlkKAogIHBsdF9zcnQsCiAgcGx0X21ldGErIGxhYnMoeT0iTG9nLW9kZHMgcmF0aW9cbm9mIGRvbWluYW50IGFsbGVsZSIpLAogIG5jb2wgPSAxLAogIGFsaWduID0gInYiLCBheGlzID0gImxyIiwKICBsYWJlbHMgPSBMRVRURVJTW2MoMSwzKV0sCiAgbGFiZWxfeCA9IC0wLjA1CikKCmNvbF8yIDwtIHBsb3RfZ3JpZCgKICBwbHRfbWF4X2FsbGVsZSwKICBwbHRfbWV0YV9jb3JyX2FiYnJldiArIGZhY2V0X2dyaWQoLiB+IGdlbm90eXBlcikgKyBsYWJzKHk9IkxvZy1vZGRzIHJhdGlvIHVzaW5nXG5wcmVkaWN0ZWQgZ2Vub3R5cGUiKSwKICBuY29sID0gMSwKICByZWxfaGVpZ2h0cyA9IGMoMSwxKSwKICBhbGlnbiA9ICJ2IiwgYXhpcyA9ICJsciIsCiAgbGFiZWxzID0gTEVUVEVSU1tjKDIsNCldLAogIGxhYmVsX3ggPSAtMC4wNQopCgpwbHRfZmlnX21haW4gPC0gcGxvdF9ncmlkKAogIE5VTEwsCiAgY29sXzEsCiAgTlVMTCwKICBjb2xfMiwKICBucm93ID0gMSwKICByZWxfd2lkdGhzID0gYygwLjI1LDMsMC4yNSw2KQopCgpwbHRfZmlnX21haW4KYGBgCgpgYGB7cn0Kc2F2ZV9wbG90KGhlcmUoImZpZ3VyZXNfcGRmL3YyLzdfc2NITEEucGRmIiksIHBsdF9maWdfbWFpbiwgYmFzZV9oZWlnaHQgPSA1LCBiYXNlX3dpZHRoID0gMTQpCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQ9NX0KcGx0X2ZpZ19zdXBwIDwtIHBsdF9tZXRhX2NvcnJfYWJicmV2ICsgZmFjZXRfZ3JpZChhY2N1cmFjeSB+IGdlbm90eXBlciwgbWFyZ2lucyA9ICJhY2N1cmFjeSIpIApwbHRfZmlnX3N1cHAKYGBgCmBgYHtyfQpzYXZlX3Bsb3QoaGVyZSgiZmlndXJlc19wZGYvdjIvczZfc2NITEEucGRmIiksIHBsdF9maWdfc3VwcCwgYmFzZV9oZWlnaHQgPSA1LCBiYXNlX3dpZHRoID0gNikKYGBgCgoKIyBTYXZlIGFsbCBmaWd1cmUgb2JqZWN0cyAKYGBge3J9Cmxpc3ROIDwtIGZ1bmN0aW9uKC4uLikgewogIGFub25MaXN0IDwtIGxpc3QoLi4uKQogIG5hbWVzKGFub25MaXN0KSA8LSBhcy5jaGFyYWN0ZXIoc3Vic3RpdHV0ZShsaXN0KC4uLikpKVstMV0KICBhbm9uTGlzdAp9CgpzYXZlUkRTKAogIGxpc3ROKHBsdF9zcnQsCiAgICAgICAgcGx0X21ldGEsCiAgICAgICAgcGx0X21heF9hbGxlbGUsCiAgICAgICAgcGx0X21ldGFfY29ycl9hYmJyZXYKICAgICAgICApLAogIGhlcmUoImZpZ3VyZXNfb2JqZWN0Lzdfc2NITEFfb2JqZWN0cy5SRFMiKQopCmBgYAoKIyBPbGQgd29yawoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gc2NfbWV0YSA8LSBmdW5jdGlvbihkZil7IC0tPgo8IS0tICAgbSA8LSBtZXRhYmluKGV2ZW50LmUgPSBvYnNlcnZlZCwgbi5lID0gZ2VuZV9zdW1fdHlwZWQsIGV2ZW50LmMgPSBleHBlY3RlZCwgbi5jID0gZ2VuZV9zdW1fdHlwZWQsIC0tPgo8IS0tICAgICAgICAgZGF0YSA9IGRmLCAtLT4KPCEtLSAgICAgICAgIG1ldGhvZCA9ICJJbnZlcnNlIiwgLS0+CjwhLS0gICAgICAgICBpbmNyID0gMC4xLCAtLT4KPCEtLSAgICAgICAgIHNtID0gIk9SIikgLS0+CjwhLS0gICBkYXRhLmZyYW1lKHN1bW1hcnkobSkkcmFuZG9tKSAlPiUgIC0tPgo8IS0tICAgICBzZWxlY3QoVEUsIHNlVEUsIGxvd2VyLCB1cHBlcikgJT4lICAtLT4KPCEtLSAgICAgbXV0YXRlX2FsbChleHApIC0tPgo8IS0tIH0gLS0+CjwhLS0gYGBgIC0tPgoKCjwhLS0gYGBge3J9IC0tPgo8IS0tIHNhbXAgPC0gIklOQ09WMVswLTJdWzAtOV0tQkwiIC0tPgo8IS0tIHggPC0gdGliYmxlKGdlbm90eXBlciA9IGMoImludml0cm8iLCAiYXJjYXNITEEiLCAib3B0aXR5cGUiLCAicGhsYXQiLCAiaGxhbWluZXIiKSkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gbWFwKGdlbm90eXBlciwgZnVuY3Rpb24oeCkgc3VwcHJlc3NNZXNzYWdlcyhyZWFkX3RzdigiLi4vLi4vY292aWQvaXNiL3NjSExBY291bnQvQkxfZmFzdHFfZmlsZXMudHh0IiwgY29sX25hbWVzID0gInNhbXBsZSIpKSkpICU+JSAgLS0+CjwhLS0gICB1bm5lc3QoZGF0YSkgJT4lICAtLT4KPCEtLSAgIGZpbHRlcihncmVwbChzYW1wLCBzYW1wbGUpKSAlPiUgIC0tPgo8IS0tICAgIyBJbXBvcnQgZGF0YSBiYXNlZCBvbiBzYW1wbGUgYW5kIGdlbm90eXBlciAtLT4KPCEtLSAgIG11dGF0ZShyZXN1bHRfcGF0aCA9IHNwcmludGYoIiVzL291dHB1dC8lcyIsc2NITEFjb3VudF9kaXIsIGdlbm90eXBlciksIC0tPgo8IS0tICAgICAgICAgIGJhcmNvZGVfcGF0aCA9IHNwcmludGYoIiVzL2JhcmNvZGVzIiwgc2NITEFjb3VudF9kaXIpKSAlPiUgIC0tPgo8IS0tICAgIyBoZWFkKDIpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gcG1hcChsaXN0KHNhbXBsZSwgcmVzdWx0X3BhdGgsIGJhcmNvZGVfcGF0aCksIGZ1bmN0aW9uKHMscixiKXsgLS0+CjwhLS0gICAgIHNjSExBX2RhdGFfcHJvY2Vzc2luZyggLS0+CjwhLS0gICAgICAgc2FtcGxlPXMsIC0tPgo8IS0tICAgICAgIHJlc3VsdF9kaXI9ciwgLS0+CjwhLS0gICAgICAgYmFyY29kZV9kaXI9YiAtLT4KPCEtLSAgICAgKSAtLT4KPCEtLSAgIH0pKSAlPiUgdW5uZXN0KGRhdGEpIC0tPgo8IS0tIHggLS0+CjwhLS0geSA8LSB4ICU+JSAgLS0+CjwhLS0gICBmaWx0ZXIoY2VsbCAlaW4lIGNlbGxfbGlzdCkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShzYW1wbGUgPSBnc3ViKCJfW0EtWl1bMC05XSQiLCIiLHNhbXBsZSkpICU+JSAgLS0+CjwhLS0gICAjICMgZmlsdGVyKG5fYWxsZWxlc19vYnNlcnZlZCA9PSAyLCBncmVwbCgiXkRbUFFSXSIsIGdlbmUpLCBzYW1wbGVJRCAlaW4lIGMoIklOQ09WMDAzLUFDIiwgIklOQ09WMDI0LUFDIikpICU+JSAgLS0+CjwhLS0gICAjIHNlbGVjdChjZWxsLCBsb2N1cywgY291bnQsIGdlbmVfc3VtX3R5cGVkLCBjZWxsdHlwZSkgJT4lICAtLT4KPCEtLSAgICMgZ3JvdXBfYnkoc2V2ZXJpdHksIGNlbGx0eXBlLCBnZW5lKSAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKGdlbmUgPT0gIkEiKSAlPiUgIC0tPgo8IS0tICAgZ3JvdXBfYnkoc2FtcGxlLCBnZW5vdHlwZXIpICU+JSAgLS0+CjwhLS0gICBzYW1wbGVfbig1MDAsIHJlcGxhY2UgPSBUKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoY29tcGxlbWVudCA9IGdlbmVfc3VtX3R5cGVkIC0gY291bnQsIGV4cGVjdGVkID0gMC41KmdlbmVfc3VtX3R5cGVkKSAlPiUgIC0tPgo8IS0tICAgcm93d2lzZSgpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUob2JzZXJ2ZWQgPSBtYXgoYWNyb3NzKGMoY291bnQsIGNvbXBsZW1lbnQpKSkpICU+JSAgLS0+CjwhLS0gICBncm91cF9ieShzYW1wbGUsIGdlbm90eXBlcikgJT4lICAtLT4KPCEtLSAgIG5lc3QoKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKGRhdGEgPSBtYXAoZGF0YSwgc2NfbWV0YSkpICU+JSAgLS0+CjwhLS0gICB1bm5lc3QoZGF0YSkgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBgYGB7ciwgZmlnLndpZHRoID0gMjQsIGZpZy5oZWlnaHQgPSA0fSAtLT4KPCEtLSB5ICU+JSAtLT4KPCEtLSAgIG11dGF0ZShnZW5vdHlwZXIgPSBmYWN0b3IoZ2Vub3R5cGVyLCBsZXZlbHMgPSBjKCJobGFtaW5lciIsInBobGF0Iiwib3B0aXR5cGUiLCJhcmNhc0hMQSIsImludml0cm8iKSkpICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKHggPSBnZW5vdHlwZXIsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIpKSsgLS0+CjwhLS0gICBnZW9tX3BvaW50KCkrIC0tPgo8IS0tICAgZ2VvbV9lcnJvcmJhcigpKyAtLT4KPCEtLSAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIpKyAtLT4KPCEtLSAgIGZhY2V0X2dyaWQoLn5zYW1wbGUsIHNjYWxlcyA9ICJmcmVlIikrIC0tPgo8IS0tICAgdGhlbWVfYncoKSsgLS0+CjwhLS0gICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKyAtLT4KPCEtLSAgIGNvb3JkX2ZsaXAoKSArIC0tPgo8IS0tICAgbGFicyh5ID0gIk9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCkgLS0+CjwhLS0gYGBgIC0tPgoKCjwhLS0gYGBge3J9IC0tPgo8IS0tIHNhbXAgPC0gIklOQ09WMDY5LUJMIiAtLT4KPCEtLSBjZWxsX2xpc3QgPC0gc3J0ICU+JSBmaWx0ZXIoY2VsbHR5cGUgPT0gImNEQyIpICU+JSBwdWxsKGNlbGwpIC0tPgo8IS0tIHggPC0gdGliYmxlKGdlbm90eXBlciA9IGMoImludml0cm8iLCAiYXJjYXNITEEiLCAib3B0aXR5cGUiLCAicGhsYXQiLCAiaGxhbWluZXIiKSkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gbWFwKGdlbm90eXBlciwgZnVuY3Rpb24oeCkgc3VwcHJlc3NNZXNzYWdlcyhyZWFkX3RzdigiLi4vLi4vY292aWQvaXNiL3NjSExBY291bnQvQkxfZmFzdHFfZmlsZXMudHh0IiwgY29sX25hbWVzID0gInNhbXBsZSIpKSkpICU+JSAgLS0+CjwhLS0gICB1bm5lc3QoZGF0YSkgJT4lICAtLT4KPCEtLSAgIGZpbHRlcihncmVwbChzYW1wLCBzYW1wbGUpKSAlPiUgIC0tPgo8IS0tICAgIyBJbXBvcnQgZGF0YSBiYXNlZCBvbiBzYW1wbGUgYW5kIGdlbm90eXBlciAtLT4KPCEtLSAgIG11dGF0ZShyZXN1bHRfcGF0aCA9IHNwcmludGYoIiVzL291dHB1dC8lcyIsc2NITEFjb3VudF9kaXIsIGdlbm90eXBlciksIC0tPgo8IS0tICAgICAgICAgIGJhcmNvZGVfcGF0aCA9IHNwcmludGYoIiVzL2JhcmNvZGVzIiwgc2NITEFjb3VudF9kaXIpKSAlPiUgIC0tPgo8IS0tICAgIyBoZWFkKDIpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gcG1hcChsaXN0KHNhbXBsZSwgcmVzdWx0X3BhdGgsIGJhcmNvZGVfcGF0aCksIGZ1bmN0aW9uKHMscixiKXsgLS0+CjwhLS0gICAgIHNjSExBX2RhdGFfcHJvY2Vzc2luZyggLS0+CjwhLS0gICAgICAgc2FtcGxlPXMsIC0tPgo8IS0tICAgICAgIHJlc3VsdF9kaXI9ciwgLS0+CjwhLS0gICAgICAgYmFyY29kZV9kaXI9YiAtLT4KPCEtLSAgICAgKSAtLT4KPCEtLSAgIH0pKSAlPiUgdW5uZXN0KGRhdGEpIC0tPgo8IS0tIHkgPC0geCAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKGNlbGwgJWluJSBjZWxsX2xpc3QpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoc2FtcGxlID0gZ3N1YigiX1tBLVpdWzAtOV0kIiwiIixzYW1wbGUpKSAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKGdlbmUgPT0gIkEiKSAlPiUgIC0tPgo8IS0tICAgZ3JvdXBfYnkoc2FtcGxlLCBnZW5vdHlwZXIpICU+JSAgLS0+CjwhLS0gICBzYW1wbGVfbig1MDAsIHJlcGxhY2UgPSBUKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoY29tcGxlbWVudCA9IGdlbmVfc3VtX3R5cGVkIC0gY291bnQsIGV4cGVjdGVkID0gMC41KmdlbmVfc3VtX3R5cGVkKSAlPiUgIC0tPgo8IS0tICAgcm93d2lzZSgpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUob2JzZXJ2ZWQgPSBtYXgoYWNyb3NzKGMoY291bnQsIGNvbXBsZW1lbnQpKSkpICU+JSAgLS0+CjwhLS0gICBncm91cF9ieShzYW1wbGUsIGdlbm90eXBlcikgJT4lICAtLT4KPCEtLSAgIG5lc3QoKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKGRhdGEgPSBtYXAoZGF0YSwgc2NfbWV0YSkpICU+JSAgLS0+CjwhLS0gICB1bm5lc3QoZGF0YSkgLS0+CjwhLS0gcGx0X21ldGEgPC0geSAlPiUgIC0tPgo8IS0tICAgdW5ncm91cCgpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoZ2Vub3R5cGVyID0gcmVmb3JtYXRfaGxhX2dlbm90eXBlcihnZW5vdHlwZXIpKSAlPiUgIC0tPgo8IS0tICAgZ2dwbG90KGFlcyh4ID0gZ2Vub3R5cGVyLCB5ID0gVEUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyKSkrIC0tPgo8IS0tICAgZ2VvbV9wb2ludCgpKyAtLT4KPCEtLSAgIGdlb21fZXJyb3JiYXIoKSsgLS0+CjwhLS0gICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsgLS0+CjwhLS0gICB0aGVtZV9idygpKyAtLT4KPCEtLSAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsgLS0+CjwhLS0gICBsYWJzKHkgPSAiT2RkcyByYXRpbyBvZiBkb21pbmFudCBhbGxlbGUiLCB4PSBOVUxMKSAtLT4KPCEtLSBwbHRfbWV0YSAgIC0tPgo8IS0tIGBgYCAtLT4KPCEtLSAjIyMgQWxsIGNsdXN0ZXJzIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gc2FtcCA8LSAiSU5DT1YwNjktQkwiIC0tPgo8IS0tIGNlbGxfbGlzdCA8LSBzcnQgJT4lIGZpbHRlcihjZWxsdHlwZSA9PSAiY0RDIikgJT4lIHB1bGwoY2VsbCkgLS0+CjwhLS0geCA8LSB0aWJibGUoZ2Vub3R5cGVyID0gYygiaW52aXRybyIsICJhcmNhc0hMQSIsICJvcHRpdHlwZSIsICJwaGxhdCIsICJobGFtaW5lciIpKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKGRhdGEgPSBtYXAoZ2Vub3R5cGVyLCBmdW5jdGlvbih4KSBzdXBwcmVzc01lc3NhZ2VzKHJlYWRfdHN2KCIuLi8uLi9jb3ZpZC9pc2Ivc2NITEFjb3VudC9CTF9mYXN0cV9maWxlcy50eHQiLCBjb2xfbmFtZXMgPSAic2FtcGxlIikpKSkgJT4lICAtLT4KPCEtLSAgIHVubmVzdChkYXRhKSAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKGdyZXBsKHNhbXAsIHNhbXBsZSkpICU+JSAgLS0+CjwhLS0gICAjIEltcG9ydCBkYXRhIGJhc2VkIG9uIHNhbXBsZSBhbmQgZ2Vub3R5cGVyIC0tPgo8IS0tICAgbXV0YXRlKHJlc3VsdF9wYXRoID0gc3ByaW50ZigiJXMvb3V0cHV0LyVzIixzY0hMQWNvdW50X2RpciwgZ2Vub3R5cGVyKSwgLS0+CjwhLS0gICAgICAgICAgYmFyY29kZV9wYXRoID0gc3ByaW50ZigiJXMvYmFyY29kZXMiLCBzY0hMQWNvdW50X2RpcikpICU+JSAgLS0+CjwhLS0gICAjIGhlYWQoMikgJT4lIC0tPgo8IS0tICAgbXV0YXRlKGRhdGEgPSBwbWFwKGxpc3Qoc2FtcGxlLCByZXN1bHRfcGF0aCwgYmFyY29kZV9wYXRoKSwgZnVuY3Rpb24ocyxyLGIpeyAtLT4KPCEtLSAgICAgc2NITEFfZGF0YV9wcm9jZXNzaW5nKCAtLT4KPCEtLSAgICAgICBzYW1wbGU9cywgLS0+CjwhLS0gICAgICAgcmVzdWx0X2Rpcj1yLCAtLT4KPCEtLSAgICAgICBiYXJjb2RlX2Rpcj1iIC0tPgo8IS0tICAgICApIC0tPgo8IS0tICAgfSkpICU+JSB1bm5lc3QoZGF0YSkgLS0+CjwhLS0gcmVzYW1wbGVfZGVwdGggPC0gNTAwIC0tPgo8IS0tIHkgPC0geCAlPiUgIC0tPgo8IS0tICAgbGVmdF9qb2luKHNydCAlPiUgc2VsZWN0KGNlbGx0eXBlLCBjZWxsKSwgYnkgPSAiY2VsbCIpICU+JSAgLS0+CjwhLS0gICBtdXRhdGUoc2FtcGxlID0gZ3N1YigiX1tBLVpdWzAtOV0kIiwiIixzYW1wbGUpKSAlPiUgIC0tPgo8IS0tICAgIyBmaWx0ZXIoZ2VuZSA9PSAiQSIpICU+JSAgLS0+CjwhLS0gICBmaWx0ZXIoIWlzLm5hKGNlbGx0eXBlKSkgJT4lICAtLT4KPCEtLSAgIHVuaXRlKCJncm91cCIsIGNlbGx0eXBlLCBnZW5lLCBzZXAgPSAiXyIsIHJlbW92ZSA9IEYpICU+JSAgLS0+CjwhLS0gICAjIG11dGF0ZShncm91cCA9IGNlbGx0eXBlKSAlPiUgIC0tPgo8IS0tICAgZ3JvdXBfYnkoZ3JvdXApICU+JSBuZXN0KCkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShkYXRhID0gbWFwKGRhdGEsIGZ1bmN0aW9uKHgpeyAtLT4KPCEtLSAgICAgeCAlPiUgIC0tPgo8IS0tICAgICAgIGdyb3VwX2J5KHNhbXBsZSwgZ2Vub3R5cGVyKSAlPiUgIC0tPgo8IS0tICAgICAgICMgc2FtcGxlX24ocmVzYW1wbGVfZGVwdGgsIHJlcGxhY2UgPSBUKSAlPiUgIC0tPgo8IS0tICAgICAgIG11dGF0ZShjb21wbGVtZW50ID0gZ2VuZV9zdW1fdHlwZWQgLSBjb3VudCwgZXhwZWN0ZWQgPSAwLjUqZ2VuZV9zdW1fdHlwZWQpICU+JSAgLS0+CjwhLS0gICAgICAgcm93d2lzZSgpICU+JSAgLS0+CjwhLS0gICAgICAgbXV0YXRlKG9ic2VydmVkID0gbWF4KGFjcm9zcyhjKGNvdW50LCBjb21wbGVtZW50KSkpKSAlPiUgIC0tPgo8IS0tICAgICAgIGdyb3VwX2J5KHNhbXBsZSwgZ2Vub3R5cGVyKSAlPiUgIC0tPgo8IS0tICAgICAgIG5lc3QoKSAlPiUgIC0tPgo8IS0tICAgICAgIG11dGF0ZShkYXRhID0gbWFwKGRhdGEsIHNjX21ldGEpKSAlPiUgIC0tPgo8IS0tICAgICAgIHVubmVzdChkYXRhKSAtLT4KPCEtLSAgIH0pKSAlPiUgIC0tPgo8IS0tICAgdW5uZXN0KGRhdGEpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodCA9IDR9IC0tPgo8IS0tIHkgPC0geSAlPiUgIC0tPgo8IS0tICAgc2VwYXJhdGUoZ3JvdXAsIGludG8gPSBjKCJjZWxsdHlwZSIsICJnZW5lIiksIHNlcCA9ICJfIikgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShncm91cCA9IGZhY3RvcihjZWxsdHlwZSwgbGV2ZWxzID0gYyggLS0+CjwhLS0gICAgICJjREMiLCAiQ0QxNCBNb25vY3l0ZSIsICJCIiwgInBEQyIsICJDRDE2IE1vbm9jeXRlIiwgIkNEOCBUIiwgIkNENCBUIiwgIk5LIiAtLT4KPCEtLSAgICkpKSAtLT4KPCEtLSB5ICU+JSAgLS0+CjwhLS0gICB1bmdyb3VwKCkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKHggPSBnZW5vdHlwZXIsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIsIGZpbGwgPSBncm91cCkpKyAtLT4KPCEtLSAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMjUpKyAtLT4KPCEtLSAgIGdlb21fZXJyb3JiYXIocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpLCB3aWR0aCA9MC41KSsgLS0+CjwhLS0gICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsgLS0+CjwhLS0gICB0aGVtZV9idygpKyAtLT4KPCEtLSAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsgLS0+CjwhLS0gICBsYWJzKHkgPSAiT2RkcyByYXRpbyBvZiBkb21pbmFudCBhbGxlbGUiLCB4PSBOVUxMKSArIC0tPgo8IS0tICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpIC0tPgoKPCEtLSB5ICU+JSAgLS0+CjwhLS0gICB1bmdyb3VwKCkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShnZW5vdHlwZXIgPSByZWZvcm1hdF9obGFfZ2Vub3R5cGVyKGdlbm90eXBlcikpICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKHggPSBnZW5vdHlwZXIsIHkgPSBURSwgeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIsIGZpbGwgPSBncm91cCkpKyAtLT4KPCEtLSAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMjUpKyAtLT4KPCEtLSAgIGdlb21fZXJyb3JiYXIocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpLCB3aWR0aCA9MC41KSsgLS0+CjwhLS0gICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsgLS0+CjwhLS0gICB0aGVtZV9idygpKyAtLT4KPCEtLSAgIGZhY2V0X3dyYXAofmdyb3VwLCBuY29sID0gNCkrIC0tPgo8IS0tICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyAtLT4KPCEtLSAgIGxhYnMoeSA9ICJPZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwpICsgLS0+CjwhLS0gICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgLS0+Cgo8IS0tIHkgJT4lICAtLT4KPCEtLSAgIHVuZ3JvdXAoKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSkgJT4lICAtLT4KPCEtLSAgIGdncGxvdChhZXMoeCA9IGdyb3VwLCB5ID0gVEUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyLCBmaWxsID0gY2VsbHR5cGUpKSsgLS0+CjwhLS0gICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjI1KSsgLS0+CjwhLS0gICBnZW9tX2Vycm9yYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgd2lkdGggPTAuNSkrIC0tPgo8IS0tICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikrIC0tPgo8IS0tICAgdGhlbWVfYncoKSsgLS0+CjwhLS0gICBmYWNldF9ncmlkKGdlbmV+Z2Vub3R5cGVyLCBzY2FsZXMgPSAiZnJlZV95IikrIC0tPgo8IS0tICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyAtLT4KPCEtLSAgIGxhYnMoeSA9ICJPZGRzIHJhdGlvIG9mIGRvbWluYW50IGFsbGVsZSIsIHg9IE5VTEwpICsgLS0+CjwhLS0gICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgLS0+Cgo8IS0tIHkgJT4lICAtLT4KPCEtLSAgIHVuZ3JvdXAoKSAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKGdyb3VwID09ICJwREMiKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKGdlbm90eXBlciA9IHJlZm9ybWF0X2hsYV9nZW5vdHlwZXIoZ2Vub3R5cGVyKSkgJT4lICAtLT4KPCEtLSAgIGdncGxvdChhZXMoeCA9IGdlbm90eXBlciwgeSA9IFRFLCB5bWluID0gbG93ZXIsIHltYXggPSB1cHBlcikpKyAtLT4KPCEtLSAgIGdlb21fcG9pbnQoKSsgLS0+CjwhLS0gICBnZW9tX2Vycm9yYmFyKCkrIC0tPgo8IS0tICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikrIC0tPgo8IS0tICAgdGhlbWVfYncoKSsgLS0+CjwhLS0gICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArIC0tPgo8IS0tICAgbGFicyh5ID0gIk9kZHMgcmF0aW8gb2YgZG9taW5hbnQgYWxsZWxlIiwgeD0gTlVMTCkgLS0+CjwhLS0gYGBgIC0tPgoKCgoKPCEtLSAjIEFzc2VtYmxlIHBsb3QgLS0+CjwhLS0gYGBge3IsIGZpZy53aWR0aCA9IDE0LCBmaWcuaGVpZ2h0ID0gNn0gLS0+CjwhLS0gIyBwbHRfYWxsZWxlX2ZyZXFfbGdkIDwtIGNvd3Bsb3Q6OmdldF9sZWdlbmQocGx0X2FsbGVsZV9mcmVxKSAtLT4KPCEtLSAjIHBsdF9tYXhfYWxsZWxlX2xnZCA8LSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9tYXhfYWxsZWxlKSAtLT4KPCEtLSBjb2xfMSA8LSBwbG90X2dyaWQoIC0tPgo8IS0tICAgcGx0X2FsbGVsZV9mcmVxLCAtLT4KPCEtLSAgIHBsdF9tYXhfYWxsZWxlLCAtLT4KPCEtLSAgIG5jb2wgPSAxLCAtLT4KPCEtLSAgIHJlbF9oZWlnaHRzID0gYyg1LDMpLCAtLT4KPCEtLSAgIGFsaWduID0gInYiLCBheGlzID0gImxyIiwgLS0+CjwhLS0gICBsYWJlbHMgPSBMRVRURVJTWzE6Ml0gLS0+CjwhLS0gKSAtLT4KCjwhLS0gY29sXzIgPC0gcGxvdF9ncmlkKCAtLT4KPCEtLSAgIHBsdF9zcnQsIC0tPgo8IS0tICAgcGx0X21ldGEsIC0tPgo8IS0tICAgbmNvbCA9IDEsIC0tPgo8IS0tICAgYWxpZ24gPSAidiIsIGF4aXMgPSAibHIiLCAtLT4KPCEtLSAgIGxhYmVscyA9IExFVFRFUlNbMzo0XSwgLS0+CjwhLS0gICBoanVzdCA9IDAuNSAtLT4KPCEtLSApIC0tPgo8IS0tIHBsb3RfZ3JpZCggLS0+CjwhLS0gICBjb2xfMSwgLS0+CjwhLS0gICBjb2xfMiwgIC0tPgo8IS0tICAgbnJvdyA9IDEsIC0tPgo8IS0tICAgcmVsX3dpZHRocyA9IGMoNiwzKSAtLT4KPCEtLSApIC0tPgo8IS0tIGBgYCAtLT4KCgoKCgoKCjwhLS0gYGBge3J9IC0tPgo8IS0tIGcgPC0gZ2dwbG90X2J1aWxkKHBsdF9zcnQpIC0tPgoKPCEtLSBwbHRfaWRzIDwtIGckZGF0YVtbMV1dIC0tPgo8IS0tIGdyb3VwX2xldmVscyA8LSBsZXZlbHMoZmFjdG9yKGckcGxvdCRkYXRhW1tnJHBsb3QkbGFiZWxzJGNvbG91cl1dKSkgLS0+Cgo8IS0tIHBsdF9rZXkgPC0gZyRkYXRhW1sxXV0gJT4lICAtLT4KPCEtLSAgIHNlbGVjdChjb2xvdXIsIGdyb3VwKSAlPiUgIC0tPgo8IS0tICAgZGlzdGluY3QoKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKGxhYmVsID0gbWFwX2Nocihncm91cCwgZnVuY3Rpb24oeCkgZ3JvdXBfbGV2ZWxzW3hdKSkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShsYWJlbCA9IGZhY3RvcihsYWJlbCwgbGV2ZWwgPSBncm91cF9sZXZlbHMpKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUobGFiZWwgPSBzcHJpbnRmKCIlcykgJXMiLCAxOm4oKSwgbGFiZWwpKSAlPiUgIC0tPgo8IS0tICAgc2VsZWN0KC1ncm91cCkgLS0+Cgo8IS0tICAgIyBsZXZlbHMoZmFjdG9yKGckcGxvdCRkYXRhW1tnJHBsb3QkbGFiZWxzJGNvbG91cl1dKSkgLS0+CjwhLS0gICAjIGRhdGEuZnJhbWUoY29sb3VycyA9IHVuaXF1ZShnJGRhdGFbWzFdXVsiY29sb3VyIl0pLCAgLS0+CjwhLS0gICAjICAgICAgICAgICAgICBsYWJlbCA9IGxldmVscyhmYWN0b3IoZyRwbG90JGRhdGFbW2ckcGxvdCRsYWJlbHMkY29sb3VyXV0pKSkgJT4lICAtLT4KCjwhLS0gcGx0X2RmIDwtIHBsdF9pZHMgJT4lICAtLT4KPCEtLSAgIGxlZnRfam9pbihwbHRfa2V5LCBieSA9ICJjb2xvdXIiKSAtLT4KCjwhLS0gcGx0X2NlbnRlciA8LSBwbHRfZGYgJT4lICAtLT4KPCEtLSAgIGdyb3VwX2J5KGxhYmVsKSAlPiUgc3VtbWFyaXNlKHggPSBtZWFuKHgpLCB5ID0gbWVhbih5KSkgJT4lIC0tPgo8IS0tICAgbXV0YXRlKGxhYmVsID0gZ3N1YigiKS4qIiwiIixsYWJlbCkpIC0tPgoKPCEtLSBwbHRfcmVwZWwgPC0gcGx0X2RmICU+JSAgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKHg9eCx5PXksY29sb3I9bGFiZWwpKSArIC0tPgo8IS0tICAgZ2VvbV9wb2ludChzaXplID0gMC41KSsgLS0+CjwhLS0gICAjIGdlb21fcG9pbnQoZGF0YSA9IHBsdF9jZW50ZXIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDIpIC0tPgo8IS0tICAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9cGx0X2NlbnRlcixhZXMobGFiZWw9bGFiZWwsICBiZy5jb2xvcj0id2hpdGUiLCBiZy5yPTAuMjUsbWluLnNlZ21lbnQubGVuZ3RoID0gMCksY29sb3IgPSAiYmxhY2siLGZvbnRmYWNlID0gImJvbGQiKSArIC0tPgo8IS0tICAgdGhlbWVfYncoKSArIC0tPgo8IS0tICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpICkgKSArIC0tPgo8IS0tICAgbGFicyh4PSJVTUFQIDEiLCB5ID0gIlVNQVAgMiIsIGNvbG9yID0gIkNlbGwgQ2x1c3RlciIpICsgLS0+CjwhLS0gICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpKyAgLS0+CjwhLS0gICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpIC0tPgo8IS0tIHBsdF9yZXBlbCAtLT4KCjwhLS0gYGBgIC0tPgoKCgoKCgo=